Data commit

This commit is contained in:
Ingy döt Net 2023-07-01 11:58:00 -04:00
parent 7387c8f97b
commit cb5bb5e222
199093 changed files with 3378972 additions and 0 deletions

View file

@ -0,0 +1,3 @@
---
from: http://rosettacode.org/wiki/Safe_addition
note: Arithmetic operations

View file

@ -0,0 +1,25 @@
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 &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>
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.
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>

View file

@ -0,0 +1,4 @@
type Interval is record
Lower : Float;
Upper : Float;
end record;

View file

@ -0,0 +1,19 @@
function "+" (A, B : Float) return Interval is
Result : constant Float := A + B;
begin
if Result < 0.0 then
if Float'Machine_Rounds then
return (Float'Adjacent (Result, Float'First), Float'Adjacent (Result, 0.0));
else
return (Float'Adjacent (Result, Float'First), Result);
end if;
elsif Result > 0.0 then
if Float'Machine_Rounds then
return (Float'Adjacent (Result, 0.0), Float'Adjacent (Result, Float'Last));
else
return (Result, Float'Adjacent (Result, Float'Last));
end if;
else -- Underflow
return (Float'Adjacent (0.0, Float'First), Float'Adjacent (0.0, Float'Last));
end if;
end "+";

View file

@ -0,0 +1,10 @@
with Ada.Text_IO; use Ada.Text_IO;
procedure Test_Interval_Addition is
-- Definitions from above
procedure Put (I : Interval) is
begin
Put (Long_Float'Image (Long_Float (I.Lower)) & "," & Long_Float'Image (Long_Float (I.Upper)));
end Put;
begin
Put (1.14 + 2000.0);
end Test_Interval_Addition;

View file

@ -0,0 +1,14 @@
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 "]"
}

View file

@ -0,0 +1,43 @@
#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;
}

View file

@ -0,0 +1,40 @@
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));
}
}
}

View file

@ -0,0 +1,50 @@
#include <fenv.h> /* fegetround(), fesetround() */
#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)
{
#pragma STDC FENV_ACCESS ON
unsigned int orig;
orig = fegetround();
fesetround(FE_DOWNWARD); /* round to -infinity */
interval[0] = a + b;
fesetround(FE_UPWARD); /* round to +infinity */
interval[1] = a + b;
fesetround(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. %.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;
}

View file

@ -0,0 +1,49 @@
#include <float.h> /* _controlfp() */
#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)
{
unsigned int orig;
orig = _controlfp(0, 0);
_controlfp(_RC_DOWN, _MCW_RC); /* round to -infinity */
interval[0] = a + b;
_controlfp(_RC_UP, _MCW_RC); /* round to +infinity */
interval[1] = a + b;
_controlfp(orig, _MCW_RC);
}
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. %.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;
}

View file

@ -0,0 +1,49 @@
#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;
}

View file

@ -0,0 +1,16 @@
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);
}

View file

@ -0,0 +1,17 @@
def makeInterval(a :float64, b :float64) {
require(a <= b)
def interval {
to least() { return a }
to greatest() { return b }
to __printOn(out) {
out.print("[", a, ", ", b, "]")
}
to add(other) {
require(a <=> b)
require(other.least() <=> other.greatest())
def result := a + other.least()
return makeInterval(result.previous(), result.next())
}
}
return interval
}

View file

@ -0,0 +1,2 @@
? makeInterval(1.14, 1.14) + makeInterval(2000.0, 2000.0)
# value: [2001.1399999999999, 2001.1400000000003]

View file

@ -0,0 +1,15 @@
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 ;

View file

@ -0,0 +1,30 @@
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))
}

View file

@ -0,0 +1,27 @@
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};
};

View file

@ -0,0 +1,4 @@
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

View file

@ -0,0 +1,20 @@
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]);
}
}

View file

@ -0,0 +1,19 @@
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]

View file

@ -0,0 +1,13 @@
// 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)}")
}

View file

@ -0,0 +1,20 @@
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"

View file

@ -0,0 +1,11 @@
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);

View file

@ -0,0 +1,55 @@
-->
<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>
<!--

View file

@ -0,0 +1,5 @@
>>> 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

View file

@ -0,0 +1,5 @@
numeric digits 1000 /*defines precision to be 1,000 decimal digits. */
y=digits() /*sets Y to existing number of decimal digits.*/
numeric digits y + y%10 /*increase the (numeric) decimal digits by 10%.*/

View file

@ -0,0 +1,27 @@
#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"))

View file

@ -0,0 +1,28 @@
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
}

View file

@ -0,0 +1,23 @@
require 'bigdecimal'
require 'bigdecimal/util' # String#to_d
def safe_add(a, b, prec)
a, b = a.to_d, b.to_d
rm = BigDecimal::ROUND_MODE
orig = BigDecimal.mode(rm)
BigDecimal.mode(rm, BigDecimal::ROUND_FLOOR)
low = a.add(b, prec)
BigDecimal.mode(rm, BigDecimal::ROUND_CEILING)
high = a.add(b, prec)
BigDecimal.mode(rm, orig)
low..high
end
[["1", "2"],
["0.1", "0.2"],
["0.1", "0.00002"],
["0.1", "-0.00002"],
].each { |a, b| puts "#{a} + #{b} = #{safe_add(a, b, 3)}" }

View file

@ -0,0 +1,13 @@
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")
}

View file

@ -0,0 +1,4 @@
let a = 1.2
let b = 0.03
print("\(a) + \(b) is in the range \((a + b).nextDown)...\((a + b).nextUp)")

View file

@ -0,0 +1,12 @@
package require critcl
package provide stepaway 1.0
critcl::ccode {
#include <math.h>
#include <float.h>
}
critcl::cproc stepup {double value} double {
return nextafter(value, DBL_MAX);
}
critcl::cproc stepdown {double value} double {
return nextafter(value, -DBL_MAX);
}

View file

@ -0,0 +1,5 @@
package require stepaway
proc safe+ {a b} {
set val [expr {double($a) + $b}]
return [list [stepdown $val] [stepup $val]]
}

View file

@ -0,0 +1,13 @@
#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))
)
}

View file

@ -0,0 +1,25 @@
/* 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))")

View file

@ -0,0 +1,83 @@
#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;
}