Safe addition: Difference between revisions

→‎{{header|E}}: Add C using fpsetround().
(→‎{{header|Python}}: Tried for pythonic equivalent.)
(→‎{{header|E}}: Add C using fpsetround().)
Line 50:
Sample output:
<pre> 2.00113989257813E+03, 2.00114013671875E+03</pre>
 
=={{header|C}}==
Most systems use the IEEE floating-point numbers. These systems have four rounding modes.
 
* Round toward zero.
* Round down (toward -infinity).
* Round to nearest.
* Round up (toward +infinity).
 
If a C program can change the rounding mode, then [a + b rounded down, a + b rounded up] solves the task. There is no portable way to change the rounding mode.
 
{{improve|C|Add solutions for C99 (using <fenv.h> to change the rounding mode) and for Microsoft Windows (using Microsoft functions in <float.h> to change the rounding mode).}}
 
=== fpsetround() ===
{{works with|OpenBSD|4.8/amd64}}
 
<lang c>#include <ieeefp.h> /* fpsetround() */
#include <stdio.h> /* printf() */
 
/*
* Calculates an interval for a + b.
* interval[0] <= a + b
* a + b <= interval[1]
*/
void
safe_add(volatile double interval[2], volatile double a, volatile double b)
{
fp_rnd orig;
 
orig = fpsetround(FP_RM); /* round to -infinity */
interval[0] = a + b;
fpsetround(FP_RP); /* round to +infinity */
interval[1] = a + b;
fpsetround(orig);
}
 
int
main()
{
const double nums[][2] = {
{1, 2},
{0.1, 0.2},
{1e100, 1e-100},
{1e308, 1e308},
};
double ival[2];
int i;
 
for (i = 0; i < sizeof(nums) / sizeof(nums[0]); i++) {
/*
* Calculate nums[i][0] + nums[i][1].
*/
safe_add(ival, nums[i][0], nums[i][1]);
 
/*
* Print the result. With OpenBSD libc, %.17g gives
* the best output; %.16g or plain %g gives not enough
* digits.
*/
printf("%.17g + %.17g =\n", nums[i][0], nums[i][1]);
printf(" [%.17g, %.17g]\n", ival[0], ival[1]);
printf(" size %.17g\n\n", ival[1] - ival[0]);
}
return 0;
}</lang>
 
Output from OpenBSD: <pre>1 + 2 =
[3, 3]
size 0
 
0.10000000000000001 + 0.20000000000000001 =
[0.29999999999999999, 0.30000000000000004]
size 5.5511151231257827e-17
 
1e+100 + 1e-100 =
[1e+100, 1.0000000000000002e+100]
size 1.9426688922257291e+84
 
1e+308 + 1e+308 =
[1.7976931348623157e+308, inf]
size inf
</pre>
 
=={{header|E}}==
Anonymous user