Safe addition: Difference between revisions

Added FreeBASIC
(→‎C99 with fesetround(): tested and added output. (code ran without changes. nice work, Kernigh))
(Added FreeBASIC)
(42 intermediate revisions by 22 users not shown)
Line 1:
{{Task|Arithmetic operations}}
Implementation of [[wp:Interval_arithmetic|interval arithmetic]] and more generally fuzzy number arithmetic require operations that yield safe upper and lower bounds of the exact result. For example, for an addition, it is the operations *↑ and *↓ defined as: ''a'' +↓ ''b'' ≤ ''a'' + ''b'' ≤ ''a'' +↑ ''b''. Additionally it is desired that the width of the interval (''a'' +↑ ''b'') - (''a'' +↓ ''b'') would be about the machine epsilon after removing the exponent part.
 
Implementation of   [[wp:Interval_arithmetic|interval arithmetic]]   and more generally fuzzy number arithmetic require operations that yield safe upper and lower bounds of the exact result.
Differently to the standard floating-point arithmetic, safe interval arithmetic is '''accurate''' (but still imprecise). I.e. the result of each defined operation contains (though does not identify) the exact mathematical outcome.
 
For example, for an addition, it is the operations &nbsp; <big> +&uarr; </big> &nbsp; and &nbsp; <big> +&darr; </big> &nbsp; defined as: &nbsp; <big> ''a'' +&darr; ''b'' &le; ''a'' + ''b'' &le; ''a'' +&uarr; ''b''. </big>
Usually a [[wp:Floating_Point_Unit|FPU's]] have machine +,-,*,/ operations accurate within the machine precision. To illustrate it, let us consider a machine with decimal floating-point arithmetic that has the precision is 3 decimal points. If the result of the machine addition is 1.23, then the exact mathematical result is within the interval ]1.22, 1.24[. When the machine rounds towards zero, then the exact result is within [1.23,1.24[. This is the basis for an implementation of safe addition.
 
Additionally it is desired that the width of the interval &nbsp; <big> (''a'' +&uarr; ''b'') - (''a'' +&darr; ''b'') </big> &nbsp; would be about the machine epsilon after removing the exponent part.
===Task===
 
Show how +&darr; and +&uarr; can be implemented in your language using the standard floating-point type. Define an interval type based on the standard floating-point one, and implement an interval-valued addition of two floating-point numbers considering them exact, in short an operation that yields the interval [''a'' +&darr; ''b'', ''a'' +&uarr; ''b''].
Differently to the standard floating-point arithmetic, safe interval arithmetic is '''accurate''' (but still imprecise).
 
I.E.: &nbsp; the result of each defined operation contains (though does not identify) the exact mathematical outcome.
 
Usually a &nbsp; [[wp:Floating_Point_Unit|FPU's]] &nbsp; have machine &nbsp; <big> +,-,*,/ </big> &nbsp; operations accurate within the machine precision.
 
To illustrate it, let us consider a machine with decimal floating-point arithmetic that has the precision is '''3''' decimal points.
 
If the result of the machine addition is &nbsp; <big> 1.23, </big> &nbsp; then the exact mathematical result is within the interval &nbsp; <big> ]1.22, 1.24[. </big>
 
When the machine rounds towards zero, then the exact result is within &nbsp; <big> [1.23,1.24[. </big> &nbsp; This is the basis for an implementation of safe addition.
 
 
;Task;
Show how &nbsp; <big> +&darr; </big> &nbsp; and &nbsp; <big> +&uarr; </big> &nbsp; can be implemented in your language using the standard floating-point type.
 
Define an interval type based on the standard floating-point one, &nbsp; and implement an interval-valued addition of two floating-point numbers considering them exact, in short an operation that yields the interval &nbsp; <big> [''a'' +&darr; ''b'', ''a'' +&uarr; ''b'']. </big>
<br><br>
 
=={{header|Ada}}==
An interval type based on Float:
<langsyntaxhighlight Adalang="ada">type Interval is record
Lower : Float;
Upper : Float;
end record;</langsyntaxhighlight>
Implementation of safe addition:
<langsyntaxhighlight Adalang="ada">function "+" (A, B : Float) return Interval is
Result : constant Float := A + B;
begin
Line 34 ⟶ 51:
return (Float'Adjacent (0.0, Float'First), Float'Adjacent (0.0, Float'Last));
end if;
end "+";</langsyntaxhighlight>
The implementation uses the attribute T'Machine_Rounds to determine if rounding is performed on inexact results. If the machine rounds a symmetric interval around the result is used. When the machine does not round, it truncates. Truncating is rounding towards zero. In this case the implementation is twice better (in terms of the result interval width), because depending on its sign, the outcome of addition can be taken for either of the bounds. Unfortunately most of modern processors are rounding.
 
Test program:
<langsyntaxhighlight Adalang="ada">with Ada.Text_IO; use Ada.Text_IO;
procedure Test_Interval_Addition is
-- Definitions from above
Line 47 ⟶ 64:
begin
Put (1.14 + 2000.0);
end Test_Interval_Addition;</langsyntaxhighlight>
Sample output:
<pre> 2.00113989257813E+03, 2.00114013671875E+03</pre>
 
=={{header|AutoHotkey}}==
<syntaxhighlight lang="ahk">Msgbox % IntervalAdd(1,2) ; [2.999999,3.000001]
 
SetFormat, FloatFast, 0.20
Msgbox % IntervalAdd(1,2) ; [2.99999999999999910000,3.00000000000000090000]
 
;In v1.0.48+, floating point variables have about 15 digits of precision internally
;unless SetFormat Float (i.e. the slow mode) is present anywhere in the script.
;In that case, the stored precision of floating point numbers is determined by A_FormatFloat.
;As there is no way for this function to know whether this is the case or not,
;it conservatively uses A_FormatFloat in all cases.
IntervalAdd(a,b){
err:=0.1**(SubStr(A_FormatFloat,3) > 15 ? 15 : SubStr(A_FormatFloat,3))
Return "[" a+b-err ","a+b+err "]"
}</syntaxhighlight>
 
=={{header|C}}==
Line 64 ⟶ 97:
 
=== C99 with fesetround() ===
<langsyntaxhighlight lang="c">#include <fenv.h> /* fegetround(), fesetround() */
#include <stdio.h> /* printf() */
Line 113 ⟶ 146:
}
return 0;
}</langsyntaxhighlight>
Output:
<pre>
Line 136 ⟶ 169:
{{works with|MinGW}}
 
<langsyntaxhighlight lang="c">#include <float.h> /* _controlfp() */
#include <stdio.h> /* printf() */
 
Line 184 ⟶ 217:
}
return 0;
}</langsyntaxhighlight>
 
=== fpsetround() ===
{{works with|OpenBSD|4.8/amd64}}
 
<langsyntaxhighlight lang="c">#include <ieeefp.h> /* fpsetround() */
#include <stdio.h> /* printf() */
 
Line 237 ⟶ 270:
}
return 0;
}</langsyntaxhighlight>
 
Output from OpenBSD: <pre>1 + 2 =
Line 255 ⟶ 288:
size inf
</pre>
 
=={{header|C sharp|C#}}==
{{trans|Java}}
<syntaxhighlight lang="csharp">using System;
 
namespace SafeAddition {
class Program {
static float NextUp(float d) {
if (d == 0.0) return float.Epsilon;
if (float.IsNaN(d) || float.IsNegativeInfinity(d) || float.IsPositiveInfinity(d)) return d;
 
byte[] bytes = BitConverter.GetBytes(d);
int dl = BitConverter.ToInt32(bytes, 0);
dl++;
bytes = BitConverter.GetBytes(dl);
 
return BitConverter.ToSingle(bytes, 0);
}
 
static float NextDown(float d) {
if (d == 0.0) return -float.Epsilon;
if (float.IsNaN(d) || float.IsNegativeInfinity(d) || float.IsPositiveInfinity(d)) return d;
 
byte[] bytes = BitConverter.GetBytes(d);
int dl = BitConverter.ToInt32(bytes, 0);
dl--;
bytes = BitConverter.GetBytes(dl);
 
return BitConverter.ToSingle(bytes, 0);
}
 
static Tuple<float, float> SafeAdd(float a, float b) {
return new Tuple<float, float>(NextDown(a + b), NextUp(a + b));
}
 
static void Main(string[] args) {
float a = 1.20f;
float b = 0.03f;
 
Console.WriteLine("({0} + {1}) is in the range {2}", a, b, SafeAdd(a, b));
}
}
}</syntaxhighlight>
{{out}}
<pre>(1.2 + 0.03) is in the range (1.23, 1.23)</pre>
 
=={{header|C++}}==
{{trans|C#}}
<syntaxhighlight lang="cpp">#include <iostream>
#include <tuple>
 
union conv {
int i;
float f;
};
 
float nextUp(float d) {
if (isnan(d) || d == -INFINITY || d == INFINITY) return d;
if (d == 0.0) return FLT_EPSILON;
 
conv c;
c.f = d;
c.i++;
 
return c.f;
}
 
float nextDown(float d) {
if (isnan(d) || d == -INFINITY || d == INFINITY) return d;
if (d == 0.0) return -FLT_EPSILON;
 
conv c;
c.f = d;
c.i--;
 
return c.f;
}
 
auto safeAdd(float a, float b) {
return std::make_tuple(nextDown(a + b), nextUp(a + b));
}
 
int main() {
float a = 1.20f;
float b = 0.03f;
 
auto result = safeAdd(a, b);
printf("(%f + %f) is in the range (%0.16f, %0.16f)\n", a, b, std::get<0>(result), std::get<1>(result));
 
return 0;
}</syntaxhighlight>
{{out}}
<pre>(1.200000 + 0.030000) is in the range (1.2299998998641968, 1.2300001382827759)</pre>
 
=={{header|D}}==
{{trans|Kotlin}}
<syntaxhighlight lang="d">import std.traits;
auto safeAdd(T)(T a, T b)
if (isFloatingPoint!T) {
import std.math; // nexDown, nextUp
import std.typecons; // tuple
return tuple!("d", "u")(nextDown(a+b), nextUp(a+b));
}
 
import std.stdio;
void main() {
auto a = 1.2;
auto b = 0.03;
 
auto r = safeAdd(a, b);
writefln("(%s + %s) is in the range %0.16f .. %0.16f", a, b, r.d, r.u);
}</syntaxhighlight>
 
{{out}}
<pre>(1.2 + 0.03) is in the range 1.2299999999999998 .. 1.2300000000000002</pre>
 
=={{header|E}}==
Line 268 ⟶ 416:
E currently inherits [[Java]]'s choices of [[IEEE]] floating point behavior, including round to nearest. Therefore, as in the Ada example, given ignorance of the actual direction of rounding, we must take one step away in ''both'' directions to get a correct interval.
 
<langsyntaxhighlight lang="e">def makeInterval(a :float64, b :float64) {
require(a <= b)
def interval {
Line 284 ⟶ 432:
}
return interval
}</langsyntaxhighlight>
 
<langsyntaxhighlight lang="e">? makeInterval(1.14, 1.14) + makeInterval(2000.0, 2000.0)
# value: [2001.1399999999999, 2001.1400000000003]</langsyntaxhighlight>
 
E provides only 64-bit "double precision" floats, and always prints them with sufficient decimal places to reproduce the original floating point number exactly.
 
=={{header|Forth}}==
{{trans|Tcl}}
<syntaxhighlight lang="forth">c-library m
s" m" add-lib
\c #include <math.h>
c-function fnextafter nextafter r r -- r
end-c-library
 
s" MAX-FLOAT" environment? drop fconstant MAX-FLOAT
 
: fstepdown ( F: r1 -- r2 )
MAX-FLOAT fnegate fnextafter ;
: fstepup ( F: r1 -- r2 )
MAX-FLOAT fnextafter ;
 
: savef+ ( F: r1 r2 -- r3 r4 ) \ r4 <= r1+r2 <= r3
f+ fdup fstepup fswap fstepdown ;</syntaxhighlight>
{{output}}
<pre>
1.2e0 3e-2 savef+ ok
17 set-precision \ to get enough digits on output ok
fs. fs. 1.2299999999999998E0 1.2300000000000002E0 ok
</pre>
 
=={{header|FreeBASIC}}==
{{trans|Go}}
<syntaxhighlight lang="vbnet">Type interval
lower As Double
upper As Double
End Type
 
Function stepAway(x As Double) As interval
Dim As interval result
result.lower = x - 0.00000000000001
result.upper = x + 0.00000000000001
Return result
End Function
 
Function safeAdd(a As Double, b As Double) As interval
Return stepAway(a + b)
End Function
 
Dim As Double a = 1.2
Dim As Double b = .03
Dim As interval result = safeAdd(a, b)
Print a; " "; b; " "; result.lower; " "; result.upper
 
Sleep</syntaxhighlight>
{{out}}
<pre> 1.2 0.03 1.22999999999999 1.23000000000001</pre>
 
=={{header|Go}}==
{{trans|Tcl}}
<syntaxhighlight lang="go">package main
 
import (
"fmt"
"math"
)
 
// type requested by task
type interval struct {
lower, upper float64
}
 
// a constructor
func stepAway(x float64) interval {
return interval {
math.Nextafter(x, math.Inf(-1)),
math.Nextafter(x, math.Inf(1))}
}
 
// function requested by task
func safeAdd(a, b float64) interval {
return stepAway(a + b)
}
 
// example
func main() {
a, b := 1.2, .03
fmt.Println(a, b, safeAdd(a, b))
}</syntaxhighlight>
Output:
<pre>
1.2 0.03 {1.2299999999999998 1.2300000000000002}
</pre>
 
=={{header|Hare}}==
{{trans|C}}
<syntaxhighlight lang="hare">use fmt;
use math;
 
type interval = struct {a: f64, b: f64};
 
export fn main() void = {
const a: [_](f64, f64) = [
(1.0f64, 2.0f64),
(0.1f64, 0.2f64),
(1e100f64, 1e-100f64),
(1e308f64, 1e308f64)];
 
for (let i = 0z; i < len(a); i += 1) {
let res = safe_add(a[i].0, a[i].1);
fmt::printfln("{} + {} is within ({}, {})", a[i].0, a[i].1, res.a, res.b)!;
};
};
 
fn safe_add(a: f64, b: f64) interval = {
let orig = math::getround();
math::setround(math::fround::DOWNWARD);
let r0 = a + b;
math::setround(math::fround::UPWARD);
let r1 = a + b;
math::setround(orig);
return interval{a = r0, b = r1};
};</syntaxhighlight>
{{out}}
<pre>
1 + 2 is within (3, 3)
0.1 + 0.2 is within (0.3, 0.30000000000000004)
1e100 + 1e-100 is within (1e100, 1.0000000000000002e100)
1e308 + 1e308 is within (1.7976931348623157e308, Infinity)
</pre>
 
=={{header|J}}==
J uses 64 bit IEEE floating points, providing 53 binary digits of accuracy.
<syntaxhighlight lang="j"> err =. 2^ 53-~ 2 <.@^. | NB. get the size of one-half unit in the last place
safeadd =. + (-,+) +&err
0j15": 1.14 safeadd 2000.0 NB. print with 15 digits after the decimal
2001.139999999999873 2001.140000000000327</syntaxhighlight>
 
=={{header|Java}}==
{{trans|Kotlin}}
<syntaxhighlight lang="java">public class SafeAddition {
private static double stepDown(double d) {
return Math.nextAfter(d, Double.NEGATIVE_INFINITY);
}
 
private static double stepUp(double d) {
return Math.nextUp(d);
}
 
private static double[] safeAdd(double a, double b) {
return new double[]{stepDown(a + b), stepUp(a + b)};
}
 
public static void main(String[] args) {
double a = 1.2;
double b = 0.03;
double[] result = safeAdd(a, b);
System.out.printf("(%.2f + %.2f) is in the range %.16f..%.16f", a, b, result[0], result[1]);
}
}</syntaxhighlight>
{{out}}
<pre>(1.20 + 0.03) is in the range 1.2299999999999998..1.2300000000000002</pre>
 
=={{header|Julia}}==
Julia has the IntervalArithmetic module, which provides arithmetic with defined precision along with the option of simply computing with actual two-number intervals:
<syntaxhighlight lang="julia">
julia> using IntervalArithmetic
 
julia> n = 2.0
2.0
 
julia> @interval 2n/3 + 1
[2.33333, 2.33334]
 
julia> showall(ans)
Interval(2.333333333333333, 2.3333333333333335)
 
julia> a = @interval(0.1, 0.3)
[0.0999999, 0.300001]
 
julia> b = @interval(0.3, 0.6)
[0.299999, 0.600001]
 
julia> a + b
[0.399999, 0.900001]
</syntaxhighlight>
 
=={{header|Kotlin}}==
{{trans|Tcl}}
<syntaxhighlight lang="scala">// version 1.1.2
 
fun stepDown(d: Double) = Math.nextAfter(d, Double.NEGATIVE_INFINITY)
 
fun stepUp(d: Double) = Math.nextUp(d)
 
fun safeAdd(a: Double, b: Double) = stepDown(a + b).rangeTo(stepUp(a + b))
 
fun main(args: Array<String>) {
val a = 1.2
val b = 0.03
println("($a + $b) is in the range ${safeAdd(a, b)}")
}</syntaxhighlight>
 
{{out}}
<pre>
(1.2 + 0.03) is in the range 1.2299999999999998..1.2300000000000002
</pre>
 
=={{header|Mathematica}}/{{header|Wolfram Language}}==
When you use //N to get a numerical result, Mathematica does what a standard calculator would do: it gives you a result to a fixed number of significant figures. You can also tell Mathematica exactly how many significant figures to keep in a particular calculation. This allows you to get numerical results in Mathematica to any degree of precision.
 
=={{header|Nim}}==
{{trans|C}}
<syntaxhighlight lang="nim">import fenv, strutils
 
proc `++`(a, b: float): tuple[lower, upper: float] =
let
a {.volatile.} = a
b {.volatile.} = b
orig = fegetround()
discard fesetround FE_DOWNWARD
result.lower = a + b
discard fesetround FE_UPWARD
result.upper = a + b
discard fesetround orig
 
proc ff(a: float): string = a.formatFloat(ffDefault, 17)
 
for x, y in [(1.0, 2.0), (0.1, 0.2), (1e100, 1e-100), (1e308, 1e308)].items:
let (d,u) = x ++ y
echo x.ff, " + ", y.ff, " ="
echo " [", d.ff, ", ", u.ff, "]"
echo " size ", (u - d).ff, "\n"</syntaxhighlight>
Output:
<pre>1.0000000000000000 + 2.0000000000000000 =
[3.0000000000000000, 3.0000000000000000]
size 0.0000000000000000
 
0.10000000000000001 + 0.20000000000000001 =
[0.29999999999999999, 0.30000000000000004]
size 5.5511151231257827e-17
 
1.0000000000000000e+100 + 1.0000000000000000e-100 =
[1.0000000000000000e+100, 1.0000000000000002e+100]
size 1.9426688922257291e+84
 
1.0000000000000000e+308 + 1.0000000000000000e+308 =
[1.7976931348623157e+308, inf]
size inf</pre>
 
=={{header|Perl}}==
There are ways avoid this whole problem (e.g. <code>Math::Decimal</code>), but another module suffices for this task.
<syntaxhighlight lang="perl">use strict;
use warnings;
use Data::IEEE754::Tools <nextUp nextDown>;
 
sub safe_add {
my($a,$b) = @_;
my $c = $a + $b;
return $c, nextDown($c), nextUp($c)
}
 
printf "%.17f (%.17f, %.17f)\n", safe_add (1/9,1/7);</syntaxhighlight>
{{out}}
<pre>0.25396825396825395 (0.25396825396825390, 0.25396825396825401)</pre>
 
=={{header|Phix}}==
{{Trans|C}}
Note the Phix printf builtin has (automatic rounding and) a built-in limit of 16 digits,
(20 digits on 64 bit) for pretty much the same reason the C version went with 17 digits,
namely that the 17th digit is so inaccurate as to be completely meaningless in normal use.<br>
Hence errors in the low,high are a bit more disguised, but as always it is the size that matters.<br>
Not surprisingly you have to get a bit down and dirty to manage this sort of stuff in Phix.
 
<!--<syntaxhighlight lang="phix">-->
<span style="color: #008080;">include</span> <span style="color: #000000;">builtins</span><span style="color: #0000FF;">\</span><span style="color: #000000;">VM</span><span style="color: #0000FF;">\</span><span style="color: #000000;">pFPU</span><span style="color: #0000FF;">.</span><span style="color: #000000;">e</span> <span style="color: #000080;font-style:italic;">-- :%down53 etc</span>
<span style="color: #008080;">function</span> <span style="color: #000000;">safe_add</span><span style="color: #0000FF;">(</span><span style="color: #004080;">atom</span> <span style="color: #000000;">a</span><span style="color: #0000FF;">,</span> <span style="color: #004080;">atom</span> <span style="color: #000000;">b</span><span style="color: #0000FF;">)</span>
<span style="color: #004080;">atom</span> <span style="color: #000000;">low</span><span style="color: #0000FF;">,</span><span style="color: #000000;">high</span>
<span style="color: #000080;font-style:italic;">-- NB: be sure to restore the usual/default rounding!</span>
#ilASM{
[32]
lea esi,[a]
call :%pLoadFlt
lea esi,[b]
call :%pLoadFlt
fld st0
call :%down53
fadd st0,st2
lea edi,[low]
call :%pStoreFlt
call :%up53
faddp
lea edi,[high]
call :%pStoreFlt
call :%near53 -- usual/default
[64]
lea rsi,[a]
call :%pLoadFlt
lea rsi,[b]
call :%pLoadFlt
fld st0
call :%down64
fadd st0,st2
lea rdi,[low]
call :%pStoreFlt
call :%up64
faddp
lea rdi,[high]
call :%pStoreFlt
call :%near64 -- usual/default
[]
}
<span style="color: #008080;">return</span> <span style="color: #0000FF;">{</span><span style="color: #000000;">low</span><span style="color: #0000FF;">,</span><span style="color: #000000;">high</span><span style="color: #0000FF;">}</span>
<span style="color: #008080;">end</span> <span style="color: #008080;">function</span>
<span style="color: #008080;">constant</span> <span style="color: #000000;">nums</span> <span style="color: #0000FF;">=</span> <span style="color: #0000FF;">{{</span><span style="color: #000000;">1</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">2</span><span style="color: #0000FF;">},</span>
<span style="color: #0000FF;">{</span><span style="color: #000000;">0.1</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">0.2</span><span style="color: #0000FF;">},</span>
<span style="color: #0000FF;">{</span><span style="color: #000000;">1e100</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">1e-100</span><span style="color: #0000FF;">},</span>
<span style="color: #0000FF;">{</span><span style="color: #000000;">1e308</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">1e308</span><span style="color: #0000FF;">}}</span>
<span style="color: #008080;">for</span> <span style="color: #000000;">i</span><span style="color: #0000FF;">=</span><span style="color: #000000;">1</span> <span style="color: #008080;">to</span> <span style="color: #7060A8;">length</span><span style="color: #0000FF;">(</span><span style="color: #000000;">nums</span><span style="color: #0000FF;">)</span> <span style="color: #008080;">do</span>
<span style="color: #004080;">atom</span> <span style="color: #0000FF;">{</span><span style="color: #000000;">a</span><span style="color: #0000FF;">,</span><span style="color: #000000;">b</span><span style="color: #0000FF;">}</span> <span style="color: #0000FF;">=</span> <span style="color: #000000;">nums</span><span style="color: #0000FF;">[</span><span style="color: #000000;">i</span><span style="color: #0000FF;">]</span>
<span style="color: #004080;">atom</span> <span style="color: #0000FF;">{</span><span style="color: #000000;">low</span><span style="color: #0000FF;">,</span><span style="color: #000000;">high</span><span style="color: #0000FF;">}</span> <span style="color: #0000FF;">=</span> <span style="color: #000000;">safe_add</span><span style="color: #0000FF;">(</span><span style="color: #000000;">a</span><span style="color: #0000FF;">,</span><span style="color: #000000;">b</span><span style="color: #0000FF;">)</span>
<span style="color: #7060A8;">printf</span><span style="color: #0000FF;">(</span><span style="color: #000000;">1</span><span style="color: #0000FF;">,</span><span style="color: #008000;">"%.16g + %.16g =\n"</span><span style="color: #0000FF;">,</span> <span style="color: #0000FF;">{</span><span style="color: #000000;">a</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">b</span><span style="color: #0000FF;">});</span>
<span style="color: #7060A8;">printf</span><span style="color: #0000FF;">(</span><span style="color: #000000;">1</span><span style="color: #0000FF;">,</span><span style="color: #008000;">" [%.16g, %.16g]\n"</span><span style="color: #0000FF;">,</span> <span style="color: #0000FF;">{</span><span style="color: #000000;">low</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">high</span><span style="color: #0000FF;">});</span>
<span style="color: #7060A8;">printf</span><span style="color: #0000FF;">(</span><span style="color: #000000;">1</span><span style="color: #0000FF;">,</span><span style="color: #008000;">" size %.16g\n\n"</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">high</span> <span style="color: #0000FF;">-</span> <span style="color: #000000;">low</span><span style="color: #0000FF;">);</span>
<span style="color: #008080;">end</span> <span style="color: #008080;">for</span>
<!--</syntaxhighlight>-->
{{out}}
<pre>
1 + 2 =
[3, 3]
size 0
 
0.1 + 0.2 =
[0.3, 0.3]
size 5.551115123125782e-17
 
1e+100 + 1e-100 =
[1e+100, 1e+100]
size 1.942668892225729e+84
 
1e+308 + 1e+308 =
[1.797693134862316e+308, inf]
size inf
</pre>
 
=={{header|PicoLisp}}==
Line 300 ⟶ 790:
Python doesn't include a module that returns an interval for safe addition, however, it does [http://docs.python.org/library/math.html#math.fsum include] a routine for performing additions of floating point numbers whilst preserving precision:
 
<langsyntaxhighlight lang="python">>>> sum([.1, .1, .1, .1, .1, .1, .1, .1, .1, .1])
0.9999999999999999
>>> from math import fsum
>>> fsum([.1, .1, .1, .1, .1, .1, .1, .1, .1, .1])
1.0</langsyntaxhighlight>
 
=={{header|Racket}}==
 
<syntaxhighlight lang="racket">
#lang racket
 
;; 1. Racket has exact unlimited integers and fractions, which can be
;; used to perform exact operations. For example, given an inexact
;; flonum, we can convert it to an exact fraction and work with that:
(define (exact+ x y)
(+ (inexact->exact x) (inexact->exact y)))
;; (A variant of this would be to keep all numbers exact, so the default
;; operations never get to inexact numbers)
 
;; 2. We can implement the required operation using a bunch of
;; functionality provided by the math library, for example, use
;; `flnext' and `flprev' to get the surrounding numbers for both
;; inputs and use them to produce the resulting interval:
(require math)
(define (interval+ x y)
(cons (+ (flprev x) (flprev y)) (+ (flnext x) (flnext y))))
(interval+ 1.14 2000.0) ; -> '(2001.1399999999999 . 2001.1400000000003)
;; (Note: I'm not a numeric expert in any way, so there must be room for
;; improvement here...)
 
;; 3. Yet another option is to use the math library's bigfloats, with an
;; arbitrary precision:
(bf-precision 1024) ; 1024 bit floats
;; add two numbers, specified as strings to avoid rounding of number
;; literals
(bf+ (bf "1.14") (bf "2000.0"))
</syntaxhighlight>
 
=={{header|Raku}}==
(formerly Perl 6)
{{works with|Rakudo|2018.12}}
 
Raku uses 64 bit IEEE floating points numbers which provide 53 binary digits
of accuracy. If you insist on using floats your answer will be accurate in the range
± 1.1102230246251565e-16. Raku actually makes it somewhat difficult to output
an exact stringified float with more than 15 digits of accuracy. It automatically
rounds since it doesn't try to pretend that it is more accurate than that.
 
If you really DO need very high precision and accuracy, Raku has native
built-in Rational number support. Rationals are the ratio of two integers, and
are always exact. Standard Rats are limited to 64 bits of precision in the
denominator. On overflow, they will downgrade to a float (Num).
FatRats have unlimited denominators.
 
There is no need to load any external libraries or force the use of Rats. Unless
you force it otherwise, decimal number are always stored as Rats as long as they
will fit within the denominator limit.
 
You can see the two integers making up the ratio of a Rat (or FatRat) using the
.nude method ('''nu'''merator, '''de'''nominator).
 
Rats and FatRats by default stringify to a fixed number of places for
non-terminating fractions and the same number of digits as the denominator for
terminating fractions. If you need more control over stringification, load the
module Rat::Precise for configurable stringification. Rat::Precise ''only'' affects
stringification, not calculation. Calculations are always done at full (exact) precision.
 
 
<syntaxhighlight lang="raku" line>say "Floating points: (Nums)";
say "Error: " ~ (2**-53).Num;
 
sub infix:<±+> (Num $a, Num $b) {
my \ε = (2**-53).Num;
$a - ε + $b, $a + ε + $b,
}
 
printf "%4.16f .. %4.16f\n", (1.14e0 ±+ 2e3);
 
say "\nRationals:";
 
say ".1 + .2 is exactly equal to .3: ", .1 + .2 === .3;
 
say "\nLarge denominators require explicit coercion to FatRats:";
say "Sum of inverses of the first 500 natural numbers:";
my $sum = sum (1..500).map: { FatRat.new(1,$_) };
say $sum;
say $sum.nude;
 
{
say "\nRat stringification may not show full precision for terminating fractions by default.";
say "Use a module to get full precision.";
use Rat::Precise; # module loading is scoped to the enclosing block
my $rat = 1.5**63;
say "\nRaku default stringification for 1.5**63:\n" ~ $rat; # standard stringification
say "\nRat::Precise stringification for 1.5**63:\n" ~$rat.precise; # full precision
}</syntaxhighlight>
{{out}}
<pre>Floating points: (Nums)
Error: 1.1102230246251565e-16
2001.1400000000000000 .. 2001.1400000000000000
 
Rationals:
.1 + .2 is exactly equal to .3: True
 
Large denominators require explicit coercion to FatRats:
Sum of inverses of the first 500 natural numbers:
6.79282342999052460298928714536797369481981381439677911664308889685435662379055049245764940373586560391756598584375065928223134688479711715030249848314807266844371012370203147722209400570479644295921001097190193214586271
(6633384299891198065461433023874214660151383488987829406868700907802279376986364154005690172480537248349310365871218591743641116766728139494727637850449054802989613344274500453825922847052235859615378238909694581687099 976528297586037954584851660253897317730151176683856787284655867127950765610716178591036797598551026470244168088645451676177520177514977827924165875515464044694152207479405310883385229609852607806002629415184926954240)
 
Rat stringification may not show full precision for terminating fractions by default.
Use a module to get full precision.
 
Raku default stringification for 1.5**63:
124093581919.64894769782737365038
 
Rat::Precise stringification for 1.5**63:
124093581919.648947697827373650380188008224280338254175148904323577880859375
</pre>
 
=={{header|REXX}}==
REXX can solve the safe addition problem by simply increasing the &nbsp; '''numeric digits''' &nbsp; (a REXX statement).
<br><br>There is effectively no limit to the number of digits, but it is
NUMERIC DIGITS (REXX statement).
constrained by how much virtual memory is (or can be) allocated.
<br><br>
<br>Eight million digits seems about a practical high end, however.
There is effectly no limit to the number of digits, but it is
<syntaxhighlight lang="rexx">numeric digits 1000 /*defines precision to be 1,000 decimal digits. */
contrained by how much virtual memory is (or can be) allocated.
<br>
Eight million digits seems about a pratical high end, however.
<lang rexx>
numeric digits 1000 /*defines precision to be 1000 digits. */
 
y=digits() /*sets Y to existing number of decimal digits.*/
 
numeric digits digits()y +digits() y%10 /*increase the (numeric) decimal digits by 10%.*/</syntaxhighlight><br><br>
</lang>
 
=={{header|Ruby}}==
Line 327 ⟶ 925:
When adding <tt>BigDecimal</tt> values, <tt>a + b</tt> is always safe. This example uses <tt>a.add(b, prec)</tt>, which is not safe because it rounds to <tt>prec</tt> digits. This example computes a safe interval by rounding to both floor and ceiling.
 
<syntaxhighlight lang="ruby">require 'bigdecimal'
{{libheader|bigdecimal}}
<lang ruby>require 'bigdecimal'
require 'bigdecimal/util' # String#to_d
 
Line 350 ⟶ 947:
["0.1", "0.00002"],
["0.1", "-0.00002"],
].each { |a, b| puts "#{a} + #{b} = #{safe_add(a, b, 3)}" }</langsyntaxhighlight>
 
Output: <pre>1 + 2 = 0.3E1..0.3E1
Line 356 ⟶ 953:
0.1 + 0.00002 = 0.1E0..0.101E0
0.1 + -0.00002 = 0.999E-1..0.1E0</pre>
 
=={{header|Scala}}==
<syntaxhighlight lang="scala">object SafeAddition extends App {
val (a, b) = (1.2, 0.03)
val result = safeAdd(a, b)
 
private def safeAdd(a: Double, b: Double) = Seq(stepDown(a + b), stepUp(a + b))
 
private def stepDown(d: Double) = Math.nextAfter(d, Double.NegativeInfinity)
 
private def stepUp(d: Double) = Math.nextUp(d)
 
println(f"($a%.2f + $b%.2f) is in the range ${result.head}%.16f .. ${result.last}%.16f")
 
}</syntaxhighlight>
 
=={{header|Swift}}==
<syntaxhighlight lang="swift">let a = 1.2
let b = 0.03
 
print("\(a) + \(b) is in the range \((a + b).nextDown)...\((a + b).nextUp)")</syntaxhighlight>
 
{{out}}
<pre>1.2 + 0.03 is in the range 1.2299999999999998...1.2300000000000002</pre>
 
=={{header|Tcl}}==
Line 361 ⟶ 982:
<br>
{{libheader|critcl}}
<langsyntaxhighlight lang="tcl">package require critcl
package provide stepaway 1.0
critcl::ccode {
Line 372 ⟶ 993:
critcl::cproc stepdown {double value} double {
return nextafter(value, -DBL_MAX);
}</langsyntaxhighlight>
With that package it's then trivial to define a "safe addition" that returns an interval as a list (lower bound, upper bound).
<langsyntaxhighlight lang="tcl">package require stepaway
proc safe+ {a b} {
set val [expr {double($a) + $b}]
return [list [stepdown $val] [stepup $val]]
}</langsyntaxhighlight>
 
 
=={{header|Transd}}==
<syntaxhighlight lang="scheme">#lang transd
 
MainModule : {
a: 1.2,
b: 0.03,
 
safeAdd: (λ d Double() e Double()
(ret [(decr (+ d e)), (incr (+ d e))])),
 
_start: (λ
(lout "(+ " a " " b ") is in the range: " prec: 20 (safeAdd a b))
)
}</syntaxhighlight>{{out}}
<pre>
(+ 1.2 0.03) is in the range: [1.2299999999999997602, 1.2300000000000002043]
</pre>
 
=={{header|Wren}}==
Wren CLI doesn't currently expose a function such as C's nextafter which is needed for this task.
 
However, if Wren is embedded in a suitable C program, then we can ask the latter to call it for us and pass back the result.
<syntaxhighlight lang="wren">/* Safe_addition.wren */
class Interval {
construct new(lower, upper) {
if (lower.type != Num || upper.type != Num) {
Fiber.abort("Arguments must be numbers.")
}
_lower = lower
_upper = upper
}
 
lower { _lower }
upper { _upper }
 
static stepAway(x) { new(nextAfter_(x, -1/0), nextAfter_(x, 1/0)) }
 
static safeAdd(x, y) { stepAway(x + y) }
 
foreign static nextAfter_(x, y) // the code for this is written in C
 
toString { "[%(_lower), %(_upper)]" }
}
 
var a = 1.2
var b = 0.03
System.print("(%(a) + %(b)) is in the range %(Interval.safeAdd(a,b))")</syntaxhighlight>
 
which we embed in the following C program and run it (using GCC 9.3.0).
 
Note that Wren's built-in print statement never displays numbers with more than 14 digit accuracy. However, if the interval bounds had been displayed directly from C with 17 digit accuracy (the maximum for the 'double' type), there would have been a marginal difference between them, namely: [1.2299999999999998, 1.2300000000000002].
<syntaxhighlight lang="c">/* gcc Safe_addition.c -o Safe_addition -lwren -lm */
 
#include <stdlib.h>
#include <stdio.h>
#include <math.h>
#include <string.h>
#include "wren.h"
 
void Interval_nextAfter(WrenVM* vm) {
double x = wrenGetSlotDouble(vm, 1);
double y = wrenGetSlotDouble(vm, 2);
wrenSetSlotDouble(vm, 0, nextafter(x, y));
}
 
WrenForeignMethodFn bindForeignMethod(
WrenVM* vm,
const char* module,
const char* className,
bool isStatic,
const char* signature) {
if (strcmp(module, "main") == 0) {
if (strcmp(className, "Interval") == 0) {
if (isStatic && strcmp(signature, "nextAfter_(_,_)") == 0) {
return Interval_nextAfter;
}
}
}
return NULL;
}
 
static void writeFn(WrenVM* vm, const char* text) {
printf("%s", text);
}
 
void errorFn(WrenVM* vm, WrenErrorType errorType, const char* module, const int line, const char* msg) {
switch (errorType) {
case WREN_ERROR_COMPILE:
printf("[%s line %d] [Error] %s\n", module, line, msg);
break;
case WREN_ERROR_STACK_TRACE:
printf("[%s line %d] in %s\n", module, line, msg);
break;
case WREN_ERROR_RUNTIME:
printf("[Runtime Error] %s\n", msg);
break;
}
}
 
char *readFile(const char *fileName) {
FILE *f = fopen(fileName, "r");
fseek(f, 0, SEEK_END);
long fsize = ftell(f);
rewind(f);
char *script = malloc(fsize + 1);
fread(script, 1, fsize, f);
fclose(f);
script[fsize] = 0;
return script;
}
 
int main() {
WrenConfiguration config;
wrenInitConfiguration(&config);
config.writeFn = &writeFn;
config.errorFn = &errorFn;
config.bindForeignMethodFn = &bindForeignMethod;
WrenVM* vm = wrenNewVM(&config);
const char* module = "main";
const char* fileName = "Safe_addition.wren";
char *script = readFile(fileName);
WrenInterpretResult result = wrenInterpret(vm, module, script);
switch (result) {
case WREN_RESULT_COMPILE_ERROR:
printf("Compile Error!\n");
break;
case WREN_RESULT_RUNTIME_ERROR:
printf("Runtime Error!\n");
break;
case WREN_RESULT_SUCCESS:
break;
}
wrenFreeVM(vm);
free(script);
return 0;
}</syntaxhighlight>
 
{{out}}
<pre>
(1.2 + 0.03) is in the range [1.23, 1.23]
</pre>
 
{{omit from|M4}}
2,122

edits