Advertisement
homer512

Schewchuk float

May 5th, 2015
309
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
C 5.48 KB | None | 0 0
  1. /*
  2.  * Copyright 2013-2015 Florian Philipp
  3.  *
  4.  * Licensed under the Apache License, Version 2.0 (the "License");
  5.  * you may not use this file except in compliance with the License.
  6.  * You may obtain a copy of the License at
  7.  *
  8.  * http://www.apache.org/licenses/LICENSE-2.0
  9.  
  10.  * Unless required by applicable law or agreed to in writing, software
  11.  * distributed under the License is distributed on an "AS IS" BASIS,
  12.  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  13.  * See the License for the specific language governing permissions and
  14.  * limitations under the License.
  15.  */
  16.  
  17.  
  18. #include <stdio.h>
  19. /* using printf */
  20. #include <stdlib.h>
  21. /* using malloc, free */
  22. #include <math.h>
  23. /* using fabsf */
  24.  
  25.  
  26. /**
  27.  * Shewchuk summation algorithm.
  28.  *
  29.  * Derived from msum here:
  30.  * http://code.activestate.com/recipes/393090/
  31.  */
  32. struct Accumulator
  33. {
  34.   /**
  35.    * Number of currently used partial sums
  36.    */
  37.   size_t partials_n;
  38.   /**
  39.    * Capacity for partial sums
  40.  
  41.    * partials_cap == 1 indicates use of partials.scalar
  42.    */
  43.   size_t partials_cap;
  44.   /**
  45.    * Partial sums ordered by value
  46.    *
  47.    * To avoid dynamic allocation in the common case that only one sum is kept,
  48.    * the scalar union member is used.
  49.    * The additional if/else comparisons have negligible effect on the run time
  50.    */
  51.   union { float* array; float scalar; } partials;
  52. };
  53.  
  54.  
  55. /**
  56.  * Initializes an Accumulator
  57.  *
  58.  * An Accumulator may only be initialized once to avoid memory leaks
  59.  * unless it is destroyed between initializations.
  60.  * See also: accumulator_reset
  61.  */
  62. void accumulator_init(struct Accumulator* self)
  63. {
  64.   self->partials_n = 0;
  65.   self->partials_cap = 1;
  66.   self->partials.scalar = 0.f;
  67. }
  68.  
  69. /**
  70.  * Releases all resources associated with this Accumulator
  71.  *
  72.  * May only be called once to avoid segfaults.
  73.  * A destroyed Accumulator may only be used after calling accumulator_init.
  74.  * As a rule of thumb, every accumulator_init should be paired with an
  75.  * accumulator_destroy
  76.  */
  77. void accumulator_destroy(struct Accumulator* self)
  78. {
  79.   if(self->partials_cap > 1)
  80.     free(self->partials.array);
  81. }
  82.  
  83. /**
  84.  * Re-initializes an Accumulator in order to use it for another summation
  85.  */
  86. void accumulator_reset(struct Accumulator* self)
  87. {
  88.   self->partials_n = 0;
  89.   if(self->partials_cap == 1)
  90.     self->partials.scalar = 0.f;
  91. }
  92.  
  93. /**
  94.  * Private method of Accumulator. Updates existing partial sums
  95.  *
  96.  * \param self an initialized Accumulator
  97.  * \param x a value to be added
  98.  * \param tail output argument. Returns the index of the last used partial sum.
  99.  * Is less or equal to self->partials_n
  100.  *
  101.  * \return the last partial sum. Has to be stored in self->partials[tail]
  102.  */
  103. static float _accumulator_update_partials(struct Accumulator* self,
  104.                       float x,
  105.                       size_t* tail)
  106. {
  107.   *tail = 0;
  108.   float* partials;
  109.   if(self->partials_cap > 1)
  110.     partials = self->partials.array;
  111.   else
  112.     partials = &self->partials.scalar;
  113.   size_t partial_i;
  114.   for(partial_i = 0; partial_i < self->partials_n; ++partial_i) {
  115.     float y = partials[partial_i];
  116.     if(fabsf(x) < fabsf(y)) {
  117.       float tmp = y;
  118.       y = x;
  119.       x = tmp;
  120.     }
  121.     float hi = x + y;
  122.     float lo = y - (hi - x);
  123.     if(lo != 0.f) {
  124.       partials[*tail] = lo;
  125.       *tail += 1;
  126.     }
  127.     x = hi;
  128.   }
  129.   return x;
  130. }
  131.  
  132. /**
  133.  * Private method of Accumulator. Extends array of partial sums if required
  134.  *
  135.  * Updates self->partials_cap and self->partials.
  136.  * May move data from self->partials.scalar to self->partials.array
  137.  *
  138.  * \param self an initialized Accumulator
  139.  * \param tail the last index that has to be used
  140.  *
  141.  * \return 0 on success. 1 if memory allocation failed
  142.  */
  143. static int _accumulator_reserve(struct Accumulator* self, size_t tail)
  144. {
  145.   if(tail < self->partials_cap)
  146.     return 0;
  147.   size_t reserved = (tail + 1) * 2;
  148.   float* partials_ext;
  149.   if(self->partials_cap == 1) {
  150.     partials_ext = malloc(reserved * sizeof(float));
  151.     if(! partials_ext)
  152.       return 1;
  153.     partials_ext[0] = self->partials.scalar;
  154.   }
  155.   else {
  156.     partials_ext = realloc(self->partials.array, reserved * sizeof(float));
  157.     if(! partials_ext)
  158.       return 1;
  159.   }
  160.   self->partials.array = partials_ext;
  161.   self->partials_cap = reserved;
  162.   return 0;
  163. }
  164.  
  165. /**
  166.  * Adds a value to the accumulated sum
  167.  *
  168.  * \return 0 on success. 1 if resource allocation failed
  169.  */
  170. int accumulator_add(struct Accumulator* self, float x)
  171. {
  172.   size_t tail;
  173.   x = _accumulator_update_partials(self, x, &tail);
  174.   if(_accumulator_reserve(self, tail))
  175.     return 1;
  176.   self->partials_n = tail + 1;
  177.   if(self->partials_cap > 1)
  178.     self->partials.array[tail] = x;
  179.   else
  180.     self->partials.scalar = x;
  181.   return 0;
  182. }
  183.  
  184. /**
  185.  * Returns the sum of all added values
  186.  *
  187.  * Note that this call has some overhead. Results should be cached
  188.  */
  189. float accumulator_sum(const struct Accumulator* self)
  190. {
  191.   if(self->partials_cap == 1)
  192.     return self->partials.scalar;
  193.   float sum = 0.f;
  194.   size_t i;
  195.   for(i = 0; i < self->partials_n; ++i)
  196.     sum += self->partials.array[i];
  197.   return sum;
  198. }
  199.  
  200. int main(void)
  201. {
  202.   float a = 1.0f;
  203.   float b = 100000000.f;
  204.   float c = -100000000.f;
  205.   double d,e,f;
  206.   struct Accumulator sum;
  207.  
  208.   d = (a + b) + c;
  209.   e = a + (b + c);
  210.   accumulator_init(&sum);
  211.   accumulator_add(&sum, a);
  212.   accumulator_add(&sum, b);
  213.   accumulator_add(&sum, c);
  214.   f = accumulator_sum(&sum);
  215.   accumulator_destroy(&sum);
  216.   printf("d=%20.20lf e=%20.20lf, f=%20.20lf\n",d, e, f);
  217.   return 0;
  218. }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement