Numeric error propagation: Difference between revisions

m
→‎{{header|Wren}}: Changed to Wren S/H
(Add swift)
m (→‎{{header|Wren}}: Changed to Wren S/H)
 
(3 intermediate revisions by 3 users not shown)
Line 45:
Specification of a generic type Approximation.Number, providing all the operations required to solve the task ... and some more operations, for completeness.
 
<langsyntaxhighlight Adalang="ada">generic
type Real is digits <>;
with function Sqrt(X: Real) return Real;
Line 92:
Sigma: Real;
end record;
end Approximation;</langsyntaxhighlight>
 
The implementation:
 
<langsyntaxhighlight Adalang="ada">with Ada.Text_IO;
 
package body Approximation is
Line 214:
end Put;
 
end Approximation;</langsyntaxhighlight>
 
Instantiating the package with Float operations, to compute the distance:
 
<langsyntaxhighlight Adalang="ada">with Approximation, Ada.Numerics.Elementary_Functions;
 
procedure Test_Approximations is
Line 234:
((X1-X2)**2 + (Y1 - Y2)**2)**0.5,
Sigma_Fore => 1);
end Test_Approximations;</langsyntaxhighlight>
 
Output:
Line 241:
=={{header|ALGOL 68}}==
{{works with|ALGOL 68G|Any - tested with release 2.8.3.win32}}
<langsyntaxhighlight lang="algol68"># MODE representing a uncertain number #
MODE UNCERTAIN = STRUCT( REAL v, uncertainty );
 
Line 313:
UNCERTAIN d = ( ( ( x1 - x2 ) ^ 2 ) + ( y1 - y2 ) ^ 2 ) ^ 0.5;
 
print( ( "distance: ", fixed( v OF d, 0, 2 ), " +/- ", fixed( uncertainty OF d, 0, 2 ), newline ) )</langsyntaxhighlight>
{{out}}
<pre>
Line 321:
=={{header|C}}==
Rewrote code to make it more compact and added a nice formatting function for imprecise values so that they are printed out in a technically correct way i.e. with the symbol '±' . Output pasted after code.
<syntaxhighlight lang="c">
<lang C>
#include <stdlib.h>
#include <string.h>
Line 397:
return 0;
}
</syntaxhighlight>
</lang>
 
<pre>
Line 408:
=={{header|C++}}==
numeric_error.hpp
<langsyntaxhighlight lang="cpp">#pragma once
 
#include <cmath>
Line 451:
private:
double v, s;
};</langsyntaxhighlight>
numeric_error.cpp
<langsyntaxhighlight lang="cpp">#include <cstdlib>
#include <iostream>
#include "numeric_error.hpp"
Line 465:
 
return EXIT_SUCCESS;
}</langsyntaxhighlight>
{{out}}
<pre>111.803398874989 ±2.938366893361</pre>
 
=={{header|Common Lisp}}==
<langsyntaxhighlight lang="lisp">(defstruct uncertain-number
(value 0 :type number)
(uncertainty 0 :type number))
Line 527:
(d (~expt (~+ (~expt (~- x1 x2) 2) (~expt (~- y1 y2) 2))
1/2)))
(format t "d = ~A~%" d)))</langsyntaxhighlight>
{{out}}
<pre>d = 111.80 ± 2.49</pre>
 
=={{header|D}}==
<langsyntaxhighlight lang="d">import std.stdio, std.math, std.string, std.typecons, std.traits;
 
const struct Imprecise {
Line 632:
writefln("Point p2: (%s, %s)", p2[0], p2[1]);
writeln("Distance(p1, p2): ", distance(p1, p2));
}</langsyntaxhighlight>
{{out}}
<pre>Point p1: (I(value=100, delta=1.1), I(value=50, delta=1.2))
Line 639:
 
=={{header|F_Sharp|F#}}==
<langsyntaxhighlight lang="fsharp">let sqr (x : float) = x * x
let abs (x : float) = System.Math.Abs x
let pow = System.Math.Pow
Line 677:
 
printfn "Distance: %A" ((((x1 %- x2) %^ 2.) %+ ((y1 %- y2) %^ 2.)) %^ 0.5)
0</langsyntaxhighlight>
{{out}}
<pre>Distance: 111.80 ±2.49</pre>
Line 684:
This version defines a new type, <code>imprecise</code>, and also defines a custom syntax similar to the syntax for complex numbers. It uses multi-methods to handle various combinations of scalar and compound values. The <code>multi-methods</code> vocabulary is described as experimental, but aside from a (probably intentional) clunky interface which requires the programmer to disambiguate generic word definitions, and the fact that multi-methods don't show up in the help browser properly, I had no issues with them. In some stress tests, they don't appear to suffer from speed issues.
{{works with|Factor|0.99 2019-10-06}}
<langsyntaxhighlight lang="factor">USING: accessors arrays fry kernel locals math math.functions
multi-methods parser prettyprint prettyprint.custom sequences ;
RENAME: GENERIC: multi-methods => MM-GENERIC:
Line 763:
PRIVATE>
 
MAIN: imprecise-demo</langsyntaxhighlight>
{{out}}
<pre>
Line 772:
 
{{works with|Factor|0.99 2019-10-06}}
<langsyntaxhighlight lang="factor">USING: arrays kernel locals math math.functions math.vectors
prettyprint sequences sequences.extras ;
IN: uncertain
Line 818:
PRIVATE>
 
MAIN: uncertain-demo</langsyntaxhighlight>
{{out}}
<pre>
Line 826:
=={{header|Fortran}}==
===Direct calculation===
Following the propagation of error estimates through a computation is a nightmare of convoluted formulae wherein mistakes are easily made. The basic method is to derive the formulae according to the standard rules while carrying forward the calculation by hand with the utmost caution. A computer can perform the calculations, but the real problem is in ensuring that it performs the correct calculations, not some misbegotten confusion... So, rather than attempt to "optimise" the calculation, the objective is to reduce brain strain by producing code whose ''checkability'' is optimised instead, somewhat as follows: <langsyntaxhighlight Fortranlang="fortran"> PROGRAM CALCULATE !A distance, with error propagation.
REAL X1, Y1, X2, Y2 !The co-ordinates.
REAL X1E,Y1E,X2E,Y2E !Their standard deviation.
Line 852:
WRITE (6,2) D,C,E !Ahh, the relief.
2 FORMAT ("Distance",F6.1,A1,F4.2) !Sizes to fit the example.
END !Enough.</langsyntaxhighlight>
This is old-style Fortran, except for the CHARACTER variable caused by problems with character codes and their screen glyphs. As can be seen, the formulae invite mistakes which is why there is no attempt to produce a single arithmetic expression for the result and its error estimate. Further, rather than attempt to emplace appropriate instances of the formula for a value raised to some power (squaring, and square root), risking all manner of misthinks, a function to do so is prepared, here using Fortran's "arithmetic statement function" protocol, expressly intended for such situations. And the results are...
<pre>
Line 865:
 
===More general===
Rather than agonise over devising adjoint formulae for the error propagation through some calculation, one can perform the desired calculation via routines that will carry along the error term, as follows:<langsyntaxhighlight Fortranlang="fortran"> MODULE ERRORFLOW !Calculate with an error estimate tagging along.
INTEGER VSP,VMAX !Do so with an arithmetic stack.
PARAMETER (VMAX = 28) !Surely sufficient.
Line 991:
WRITE (6,2) STACKV(1),PM,STACKE(1) !Ahh, the relief.
2 FORMAT ("Distance",F6.1,A1,F4.2) !Sizes to fit the example.
END !Enough.</langsyntaxhighlight>
This is closer to the idea of extending the language to supply additional facilities. At the cost of hand-compiling the arithmetic expression into a sequence of pseudo-machine code subroutines, it is apparent that the mind-tangling associated error formulae need no longer be worried over. The various arithmetic subroutines have to be coded correctly with careful attention to the V or E statements in fact being for the V and E terms (cut&paste followed by inadequate adjustment the culprit here: such mistakes are less likely when using a card punch because copying is more troublesome), but this is a straightforward matter of checking. And indeed the VPOW(2) routine has the same effect as VSQUARE. Output:
<pre>
Line 1,014:
 
===Fortran 90 ''et seq''.===
A latter-day expansion of Fortran makes it possible to define a compound entity such as a value and its associated error, for instance,<langsyntaxhighlight Fortranlang="fortran"> TYPE DATUM
REAL VALUE
REAL SD
Line 1,023:
END TYPE POINT
TYPE(POINT) P1,P2
</syntaxhighlight>
</lang>
Whereupon, instead of a swarm of separate variables named according to some scheme, you can have a collection of variables with subcomponents named systematically. Further, via a great deal of syntax one can devise functions dealing with those compound types and moreover, prepare procedures that will perform operations such as addition and subtraction, etc. and merge these with the ordinary usages of addition, etc. of ordinary variables. One would then write the formula to be calculated, and it would all just happen. This has been done for arithmetic with rational numbers, in [[Arithmetic/Rational#Fortran]] for example.
 
Line 1,029:
 
=={{header|FreeBASIC}}==
<langsyntaxhighlight lang="freebasic">'----------------------
' definition of a "measurement" type with value and uncartainty
' and operators that can operate on them
Line 1,137:
y2.unc = 2.3
 
printm( ((x1-x2)^2 + (y1-y2)^2)^0.5 )</langsyntaxhighlight>
{{out}}<pre>
111.80340 +- 2.4872
Line 1,144:
=={{header|Go}}==
Variance from task requirements is that the following does not "extend the language." It simply defines a type with associated functions and methods as required to solve the remainder of the task.
<langsyntaxhighlight lang="go">package main
 
import (
Line 1,244:
fmt.Println("d: ", d.n)
fmt.Println("error:", d.errorTerm())
}</langsyntaxhighlight>
Output:
<pre>
Line 1,252:
 
=={{header|Haskell}}==
<langsyntaxhighlight lang="haskell">data Error a = Error {value :: a, uncertainty :: a} deriving (Eq, Show)
 
instance (Floating a) => Num (Error a) where
Line 1,272:
x2 = Error 200 2.2
y2 = Error 100 2.3
</syntaxhighlight>
</lang>
{{out}}
<pre>Error {value = 111.80339887498948, uncertainty = 2.4871670631463423}</pre>
Line 1,280:
The following solution works in both languages.
 
<langsyntaxhighlight lang="unicon">record num(val,err)
 
procedure main(a)
Line 1,322:
return (numeric(a)^numeric(b)) |
num(f := a.val^numeric(b), abs(f*b*(a.err/a.val)))
end</langsyntaxhighlight>
 
The output is:
Line 1,338:
First, we will need some utilities. <code>num</code> will extract the number part of a number. <code>unc</code> will extract the uncertainty part of a number, and will also be used to associate uncertainty with a number. <code>dist</code> will compute the distance between two numbers (which is needed for multiplicative uncertainty).
 
<langsyntaxhighlight lang="j">num=: {."1
unc=: {:@}."1 : ,.
dist=: +/&.:*:</langsyntaxhighlight>
 
Note that if a number has no uncertainty assigned to it, we assume the uncertainty is zero.
Line 1,346:
Jumping into the example values, for illustration purposes:
 
<langsyntaxhighlight lang="j">x1=: 100 unc 1.1
y1=: 50 unc 1.2
 
x2=: 200 unc 2.2
y2=: 100 unc 2.3</langsyntaxhighlight>
 
Above, we see <code>unc</code> being used to associate a number with its uncertainty. Here's how to take them apart again:
 
<langsyntaxhighlight lang="j"> num x1
100
unc x1
1.1</langsyntaxhighlight>
 
Note that these operations "do the right thing" for normal numbers:
 
<langsyntaxhighlight lang="j"> num 100
100
unc 100
0</langsyntaxhighlight>
 
And, a quick illustration of the distance function:
<syntaxhighlight lang="text"> 3 dist 4
5</langsyntaxhighlight>
 
Next, we need to define our arithmetic operations:
 
<langsyntaxhighlight lang="j">add=: +&num unc dist&unc
sub=: -&num unc dist&unc
mul=: *&num unc |@(*&num * dist&(unc%num))
div=: %&num unc |@(%&num * dist&(unc%num))
exp=: ^&num unc |@(^&num * dist&(unc%num))</langsyntaxhighlight>
 
Finally, our required example:
 
<langsyntaxhighlight lang="j"> exp&0.5 (x1 sub x2) add&(exp&2) y1 sub y2
111.803 2.48717</langsyntaxhighlight>
 
=={{header|Java}}==
<langsyntaxhighlight lang="java">public class Approx {
private double value;
private double error;
Line 1,470:
System.out.println(x1);
}
}</langsyntaxhighlight>
{{out}}
<pre>111.80339887498948±2.4871670631463423</pre>
Line 1,476:
=={{header|Julia}}==
=== Using Measurements library ===
<langsyntaxhighlight lang="julia">
using Measurements
 
Line 1,488:
@show d
@show d.val, d.err
</langsyntaxhighlight>{{out}}
The Measurements library will round to correct decimal place precision when displaying tolerances, so the fields are shown to show the calculations are equivalent.
<pre>
Line 1,496:
 
=== With custom module ===
<langsyntaxhighlight lang="julia">module NumericError
 
import Base: convert, promote_rule, +, -, *, /, ^
Line 1,555:
 
@show x1 y1 x2 y2 sqrt((x1 - x2) ^ 2 + (y1 - y2) ^ 2)
</syntaxhighlight>
</lang>
 
{{out}}
Line 1,568:
=={{header|Kotlin}}==
{{trans|Java}}
<langsyntaxhighlight lang="scala">import java.lang.Math.*
 
data class Approx(val ν: Double, val σ: Double = 0.0) {
Line 1,607:
val y2 = Approx(100.0, 2.3)
println(((x1 - x2).pow(2.0) + (y1 - y2).pow(2.0)).pow(0.5))
}</langsyntaxhighlight>
{{out}}
<pre>111.80339887498948 ±2.4871670631463423</pre>
 
=={{header|Mathematica}}/{{header|Wolfram Language}}==
<langsyntaxhighlight lang="mathematica">PlusMinus /: a_ ± σa_ + c_?NumericQ := N[(a + c) ± σa];
PlusMinus /: a_ ± σa_ + b_ ± σb_ := N[(a + b) ± Norm@{σa, σb}];
PlusMinus /: c_?NumericQ (a_ ± σa_) := N[c a ± Abs[c σa]];
PlusMinus /: (a_ ± σa_) (b_ ± σb_) := N[a b ± (a b Norm@{σa/a, σb/b})^2];
PlusMinus /: (a_ ± σa_)^c_?NumericQ := N[a^c ± Abs[a^c σa/a]];</langsyntaxhighlight>
<langsyntaxhighlight lang="mathematica">x1 = 100 ± 1.1;
y1 = 50 ± 1.2;
x2 = 200 ± 2.2;
y2 = 100 ± 2.3;
d = Sqrt[(x1 - x2)^2 + (y1 - y2)^2]</langsyntaxhighlight>
{{Out}}
<pre>111.803 ± 2.48717</pre>
===Native implementation===
<langsyntaxhighlight Mathematicalang="mathematica">x1 = Around[100, 1.1];
y1 = Around[50, 1.2];
x2 = Around[200, 2.2];
y2 = Around[100, 2.3];
d = Sqrt[(x1 - x2)^2 + (y1 - y2)^2]</langsyntaxhighlight>
{{out}}
<pre>111.8\[PlusMinus]2.5</pre>
 
=={{header|Nim}}==
<langsyntaxhighlight Nimlang="nim">import strformat
import math
 
Line 1,675:
var y2 = Imprecise(x: 100, σ: 2.3)
 
echo sqrt((x1 - x2) ^ 2 + (y1 - y2) ^ 2)</langsyntaxhighlight>
{{out}}
<pre>
Line 1,683:
=={{header|PARI/GP}}==
''This is a work-in-progress.''
<langsyntaxhighlight lang="parigp">add(a,b)=if(type(a)==type(b), a+b, if(type(a)=="t_VEC",a+[b,0],b+[a,0]));
sub(a,b)=if(type(a)==type(b), [a[1]-b[1],a[2]+b[2]], if(type(a)=="t_VEC",a-[b,0],[a,0]-b));
mult(a,b)=if(type(a)=="t_VEC", if(type(b)=="t_VEC", [a[1]*b[1], abs(a[1]*b[1])*sqrt(norml2([a[2]/a[1],b[2]/b[1]]))], [b*a[1], abs(b)*a[2]]), [a*b[1], abs(a)*b[2]]);
Line 1,689:
pow(a,b)=[a[1]^b, abs(a[1]^b*b*a[2]/a[1])];
x1=[100,1.1];y1=[50,1.2];x2=[200,2.2];y2=[100,2.3];
pow(add(pow(sub(x1,x2),2),pow(sub(y1,y2),2)),.5)</langsyntaxhighlight>
 
=={{header|Perl}}==
Following code keeps track of covariance between variables. Each variable with error contains its mean value and components of error source from a set of indepententindependent variables. It's more than what the task requires.
<langsyntaxhighlight lang="perl">use utf8v5.36;
 
package ErrVar;
use strict;
 
# helper function, apply function 'f' to pairs (a, b) from listX and listY
sub zip (&$f, $x, $y) {
my ($f, $x, $y) =my @_out;
$y = [(0) x @$x] unless @$y; # if not defined
my $l = $#$x;
if ($l < push @out, $#f->($x->[$_], $y->[$_]) {for $l0 =.. $#$y }x;
\@out
 
my @out;
for (0 .. $l) {
local $a = $x->[$_];
local $b = $y->[$_];
push @out, $f->();
}
\@out
}
 
use overload
'""' => \&_str,
'+' => \&_add,
'-' => \&_sub,
'*' => \&_mul,
'/' => \&_div,
'bool' => \&_bool,
'<=>' => \&_ncmp,
'neg' => \&_neg,
'sqrt' => \&_sqrt,
'sqrtlog' => \&_sqrt_log,
'logexp' => \&_log_exp,
'exp**' => \&_exp_pow,
'**' => \&_pow,
;
 
# make a variable with mean value and a list of coefficient to
# variables providing independent errors
sub make ($x, @v) { bless [$x, @v] }
my $x = shift;
bless [$x, [@{+shift}]]
}
 
sub _str { sprintf "%g±%.3g", $_[0][0], sigma($_[0]) }
 
# mean value of the var, or just the input if it's not of this class
sub mean ($x) { ref $x && $x->isa(__PACKAGE__) ? $x->[0] : $x }
sub mean {
my $x = shift;
ref($x) && $x->isa(__PACKAGE__) ? $x->[0] : $x
}
 
# return variance index array
sub vlist ($x) { ref $x && $x->isa(__PACKAGE__) ? $x->[1] : [] }
sub vlist {
my $x = shift;
ref($x) && $x->isa(__PACKAGE__) ? $x->[1] : [];
}
 
sub variance ($x) {
return 0 unless ref($x) and $x->isa(__PACKAGE__);
my $x = shift;
my $s;
return 0 unless ref($x) and $x->isa(__PACKAGE__);
$s += $_ * $_ for @{$x->[1]};
my $s;
$s
$s += $_ * $_ for (@{$x->[1]});
$s
}
 
sub covariance ($x, $y) {
return 0 unless ref($x) && $x->isa(__PACKAGE__);
my ($x, $y) = @_;
return 0 unless ref($xy) && $xy->isa(__PACKAGE__);
my $s;
return 0 unless ref($y) && $y->isa(__PACKAGE__);
zip sub ($a,$b) { $s += $a * $b }, vlist($x), vlist($y);
 
my $s;
zip { $s += $a * $b } vlist($x), vlist($y);
$s
}
 
sub sigma ($v) { sqrt variance(shift) $v }
 
# to determine if a var is probably zero. we use 1σ here
sub _bool ($x, $, $) {
abs(mean $x) > sigma $x
my $x = shift;
return abs(mean($x)) > sigma($x);
}
 
sub _ncmp ($a, $b, $) {
return 0 unless my $x = shift()$a - shift() or return 0$b;
return mean($x) > 0 ? 1 : -1;
}
 
sub _neg ($x, $, $) {
bless [ -mean($x), [map(-$_, @{vlist $x}) ] ];
my $x = shift;
bless [ -mean($x), [map(-$_, @{vlist($x)}) ] ];
}
 
sub _add ($x, $y, $) {
my ($xx0, $yy0) = @_( mean($x), mean($y));
my ($x0xv, $y0yv) = (meanvlist($x), meanvlist($y));
bless [$x0 + $y0, zip sub ($a,$b) {$a + $b}, $xv, $yv]
my ($xv, $yv) = (vlist($x), vlist($y));
bless [$x0 + $y0, zip {$a + $b} $xv, $yv];
}
 
sub _sub ($x, $y, $) {
my ($xx0, $y,y0) = ( mean($swapx), = @_mean($y));
if ($swap) { my ($xxv, $yyv) = (vlist($yx), vlist($xy) });
my ( bless [$x0, - $y0), =zip sub (mean($xa,$b) {$a - $b}, mean($y));xv, $yv]
my ($xv, $yv) = (vlist($x), vlist($y));
bless [$x0 - $y0, zip {$a - $b} $xv, $yv];
}
 
sub _mul ($x, $y, $) {
my ($xx0, $yy0) = @_( mean($x), mean($y));
my ($x0xv, $y0yv) = (meanvlist($x), meanvlist($y));
my ( $xv, $yv) = (vlist[ map($x)y0 * $_, vlist(@$y)xv) ];
$yv = [ map($x0 * $_, @$yv) ];
 
$xv = bless [$x0 * map($y0, *zip sub ($_a,$b) {$a + $b}, @$xv), $yv];
$yv = [ map($x0 * $_, @$yv) ];
 
bless [$x0 * $y0, zip {$a + $b} $xv, $yv];
}
 
sub _div ($x, $y, $) {
my ($xx0, $y,y0) = ( mean($swapx), = @_mean($y));
if ($swap) { my ($xxv, $yyv) = (vlist($yx), vlist($xy) });
$xv = [ map($_/$y0, @$xv) ];
 
my ($x0, $y0)yv = (mean[ map($x)x0 * $_/$y0/$y0, mean(@$y)yv) ];
bless [$x0 / $y0, zip sub ($a,$b) {$a + $b}, $xv, $yv]
my ($xv, $yv) = (vlist($x), vlist($y));
 
$xv = [ map($_/$y0, @$xv) ];
$yv = [ map($x0 * $_/$y0/$y0, @$yv) ];
 
bless [$x0 / $y0, zip {$a + $b} $xv, $yv];
}
 
sub _sqrt ($x, $, $) {
my ($x0, $xv) = ( mean($x), vlist($x) );
my $x = shift;
my $x0 = meansqrt($xx0);
my $xv = vlist[ map($x_ / 2 / $x0, @$xv) ];
bless [$x0, $xv]
$x0 = sqrt($x0);
$xv = [ map($_ / 2 / $x0, @$xv) ];
bless [$x0, $xv]
}
 
sub _pow ($x, $y, $) {
my if ($x, $y,< $swap0) = @_;{
die "Can't take pow of negative number $x" if int($y) != $y or $y & 1;
if ($swap) { ($x, $y) = ($y, $x) }
if ( $x <= 0) {-$x;
}
if (int($y) != $y || ($y & 1)) {
exp($y * log $x)
die "Can't take pow of negative number $x";
}
$x = -$x;
}
exp($y * log $x)
}
 
sub _exp ($x, $, $) {
my ($x0, $xv) = ( exp(mean($x)), vlist($x) );
my $x = shift;
bless [ $x0, [map($x0 * $_, @$xv) ] ]
my $x0 = exp(mean($x));
my $xv = vlist($x);
bless [ $x0, [map($x0 * $_, @$xv) ] ]
}
 
sub _log ($x, $, $) {
my ($x0, $xv) = ( mean($x), vlist($x) );
my $x = shift;
bless [ log($x0), [ map($_ / $x0, @$xv) ] ]
my $x0 = mean($x);
my $xv = vlist($x);
bless [ log($x0), [ map($_ / $x0, @$xv) ] ]
}
 
sub _str { sprintf '%g±%.3g', $_[0][0], sigma($_[0]) }
"If this package were to be in its own file, you need some truth value to end it like this.";
 
package main;
Line 1,873 ⟶ 1,828:
 
my $z1 = sqrt(($x1 - $x2) ** 2 + ($y1 - $y2) ** 2);
printsay "distance: $z1\n\n";
 
# this is not for task requirement
my $a = $x1 + $x2;
my $b = $y1 - 2 * $x2;
printsay "covariance between $a and $b: ", $a->covariance($b), "\n";</langsyntaxhighlight>output<lang>distance: 111.803±2.49
{{out}}
 
<pre>distance: 111.803±2.49
covariance between 300±2.46 and -350±4.56: -9.68</lang>
covariance between 300±2.46 and -350±4.56: -9.68</pre>
 
=={{header|Phix}}==
<!--<syntaxhighlight lang="phix">(phixonline)-->
<lang Phix>enum VALUE, DELTA
<span style="color: #008080;">with</span> <span style="color: #008080;">javascript_semantics</span>
 
<span style="color: #008080;">enum</span> <span style="color: #000000;">VALUE</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">DELTA</span>
type imprecise(object imp)
return sequence(imp) and atom(imp[VALUE]) and atom(imp[DELTA])
<span style="color: #008080;">type</span> <span style="color: #000000;">imprecise</span><span style="color: #0000FF;">(</span><span style="color: #004080;">object</span> <span style="color: #000000;">imp</span><span style="color: #0000FF;">)</span>
end type
<span style="color: #008080;">return</span> <span style="color: #004080;">sequence</span><span style="color: #0000FF;">(</span><span style="color: #000000;">imp</span><span style="color: #0000FF;">)</span> <span style="color: #008080;">and</span> <span style="color: #004080;">atom</span><span style="color: #0000FF;">(</span><span style="color: #000000;">imp</span><span style="color: #0000FF;">[</span><span style="color: #000000;">VALUE</span><span style="color: #0000FF;">])</span> <span style="color: #008080;">and</span> <span style="color: #004080;">atom</span><span style="color: #0000FF;">(</span><span style="color: #000000;">imp</span><span style="color: #0000FF;">[</span><span style="color: #000000;">DELTA</span><span style="color: #0000FF;">])</span>
 
<span style="color: #008080;">end</span> <span style="color: #008080;">type</span>
function sqr(atom a)
return a*a
<span style="color: #008080;">function</span> <span style="color: #000000;">sqr</span><span style="color: #0000FF;">(</span><span style="color: #004080;">atom</span> <span style="color: #000000;">a</span><span style="color: #0000FF;">)</span>
end function
<span style="color: #008080;">return</span> <span style="color: #000000;">a</span><span style="color: #0000FF;">*</span><span style="color: #000000;">a</span>
 
<span style="color: #008080;">end</span> <span style="color: #008080;">function</span>
function imprecise_add(imprecise a, b)
atom delta = sqrt(sqr(a[DELTA]) + sqr(b[DELTA]))
<span style="color: #008080;">function</span> <span style="color: #000000;">imprecise_add</span><span style="color: #0000FF;">(</span><span style="color: #000000;">imprecise</span> <span style="color: #000000;">a</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">b</span><span style="color: #0000FF;">)</span>
imprecise ret = {a[VALUE] + b[VALUE], delta}
<span style="color: #004080;">atom</span> <span style="color: #000000;">delta</span> <span style="color: #0000FF;">=</span> <span style="color: #7060A8;">sqrt</span><span style="color: #0000FF;">(</span><span style="color: #000000;">sqr</span><span style="color: #0000FF;">(</span><span style="color: #000000;">a</span><span style="color: #0000FF;">[</span><span style="color: #000000;">DELTA</span><span style="color: #0000FF;">])</span> <span style="color: #0000FF;">+</span> <span style="color: #000000;">sqr</span><span style="color: #0000FF;">(</span><span style="color: #000000;">b</span><span style="color: #0000FF;">[</span><span style="color: #000000;">DELTA</span><span style="color: #0000FF;">]))</span>
return ret
<span style="color: #000000;">imprecise</span> <span style="color: #000000;">ret</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;">VALUE</span><span style="color: #0000FF;">]</span> <span style="color: #0000FF;">+</span> <span style="color: #000000;">b</span><span style="color: #0000FF;">[</span><span style="color: #000000;">VALUE</span><span style="color: #0000FF;">],</span> <span style="color: #000000;">delta</span><span style="color: #0000FF;">}</span>
end function
<span style="color: #008080;">return</span> <span style="color: #000000;">ret</span>
<span style="color: #008080;">end</span> <span style="color: #008080;">function</span>
function imprecise_mul(imprecise a, b)
atom delta = sqrt(sqr(a[VALUE]*b[DELTA]) + sqr(b[VALUE]*a[DELTA]))
<span style="color: #008080;">function</span> <span style="color: #000000;">imprecise_mul</span><span style="color: #0000FF;">(</span><span style="color: #000000;">imprecise</span> <span style="color: #000000;">a</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">b</span><span style="color: #0000FF;">)</span>
imprecise ret = {a[VALUE] * b[VALUE],delta}
<span style="color: #004080;">atom</span> <span style="color: #000000;">delta</span> <span style="color: #0000FF;">=</span> <span style="color: #7060A8;">sqrt</span><span style="color: #0000FF;">(</span><span style="color: #000000;">sqr</span><span style="color: #0000FF;">(</span><span style="color: #000000;">a</span><span style="color: #0000FF;">[</span><span style="color: #000000;">VALUE</span><span style="color: #0000FF;">]*</span><span style="color: #000000;">b</span><span style="color: #0000FF;">[</span><span style="color: #000000;">DELTA</span><span style="color: #0000FF;">])</span> <span style="color: #0000FF;">+</span> <span style="color: #000000;">sqr</span><span style="color: #0000FF;">(</span><span style="color: #000000;">b</span><span style="color: #0000FF;">[</span><span style="color: #000000;">VALUE</span><span style="color: #0000FF;">]*</span><span style="color: #000000;">a</span><span style="color: #0000FF;">[</span><span style="color: #000000;">DELTA</span><span style="color: #0000FF;">]))</span>
return ret
<span style="color: #000000;">imprecise</span> <span style="color: #000000;">ret</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;">VALUE</span><span style="color: #0000FF;">]</span> <span style="color: #0000FF;">*</span> <span style="color: #000000;">b</span><span style="color: #0000FF;">[</span><span style="color: #000000;">VALUE</span><span style="color: #0000FF;">],</span><span style="color: #000000;">delta</span><span style="color: #0000FF;">}</span>
end function
<span style="color: #008080;">return</span> <span style="color: #000000;">ret</span>
<span style="color: #008080;">end</span> <span style="color: #008080;">function</span>
function imprecise_div(imprecise a, b)
atom delta = sqrt(sqr(a[VALUE]*b[DELTA]) + sqr(b[VALUE]*a[DELTA]))/sqr(b[VALUE])
<span style="color: #008080;">function</span> <span style="color: #000000;">imprecise_div</span><span style="color: #0000FF;">(</span><span style="color: #000000;">imprecise</span> <span style="color: #000000;">a</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">b</span><span style="color: #0000FF;">)</span>
imprecise ret = {a[VALUE] / b[VALUE], delta}
<span style="color: #004080;">atom</span> <span style="color: #000000;">delta</span> <span style="color: #0000FF;">=</span> <span style="color: #7060A8;">sqrt</span><span style="color: #0000FF;">(</span><span style="color: #000000;">sqr</span><span style="color: #0000FF;">(</span><span style="color: #000000;">a</span><span style="color: #0000FF;">[</span><span style="color: #000000;">VALUE</span><span style="color: #0000FF;">]*</span><span style="color: #000000;">b</span><span style="color: #0000FF;">[</span><span style="color: #000000;">DELTA</span><span style="color: #0000FF;">])</span> <span style="color: #0000FF;">+</span> <span style="color: #000000;">sqr</span><span style="color: #0000FF;">(</span><span style="color: #000000;">b</span><span style="color: #0000FF;">[</span><span style="color: #000000;">VALUE</span><span style="color: #0000FF;">]*</span><span style="color: #000000;">a</span><span style="color: #0000FF;">[</span><span style="color: #000000;">DELTA</span><span style="color: #0000FF;">]))/</span><span style="color: #000000;">sqr</span><span style="color: #0000FF;">(</span><span style="color: #000000;">b</span><span style="color: #0000FF;">[</span><span style="color: #000000;">VALUE</span><span style="color: #0000FF;">])</span>
return ret
<span style="color: #000000;">imprecise</span> <span style="color: #000000;">ret</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;">VALUE</span><span style="color: #0000FF;">]</span> <span style="color: #0000FF;">/</span> <span style="color: #000000;">b</span><span style="color: #0000FF;">[</span><span style="color: #000000;">VALUE</span><span style="color: #0000FF;">],</span> <span style="color: #000000;">delta</span><span style="color: #0000FF;">}</span>
end function
<span style="color: #008080;">return</span> <span style="color: #000000;">ret</span>
<span style="color: #008080;">end</span> <span style="color: #008080;">function</span>
function imprecise_pow(imprecise a, atom c)
atom v = power(a[VALUE], c),
<span style="color: #008080;">function</span> <span style="color: #000000;">imprecise_pow</span><span style="color: #0000FF;">(</span><span style="color: #000000;">imprecise</span> <span style="color: #000000;">a</span><span style="color: #0000FF;">,</span> <span style="color: #004080;">atom</span> <span style="color: #000000;">c</span><span style="color: #0000FF;">)</span>
delta = abs(v*c*a[DELTA]/a[VALUE])
<span style="color: #004080;">atom</span> <span style="color: #000000;">v</span> <span style="color: #0000FF;">=</span> <span style="color: #7060A8;">power</span><span style="color: #0000FF;">(</span><span style="color: #000000;">a</span><span style="color: #0000FF;">[</span><span style="color: #000000;">VALUE</span><span style="color: #0000FF;">],</span> <span style="color: #000000;">c</span><span style="color: #0000FF;">),</span>
imprecise ret = {v,delta}
<span style="color: #000000;">delta</span> <span style="color: #0000FF;">=</span> <span style="color: #7060A8;">abs</span><span style="color: #0000FF;">(</span><span style="color: #000000;">v</span><span style="color: #0000FF;">*</span><span style="color: #000000;">c</span><span style="color: #0000FF;">*</span><span style="color: #000000;">a</span><span style="color: #0000FF;">[</span><span style="color: #000000;">DELTA</span><span style="color: #0000FF;">]/</span><span style="color: #000000;">a</span><span style="color: #0000FF;">[</span><span style="color: #000000;">VALUE</span><span style="color: #0000FF;">])</span>
return ret
<span style="color: #000000;">imprecise</span> <span style="color: #000000;">ret</span> <span style="color: #0000FF;">=</span> <span style="color: #0000FF;">{</span><span style="color: #000000;">v</span><span style="color: #0000FF;">,</span><span style="color: #000000;">delta</span><span style="color: #0000FF;">}</span>
end function
<span style="color: #008080;">return</span> <span style="color: #000000;">ret</span>
<span style="color: #008080;">end</span> <span style="color: #008080;">function</span>
function printImprecise(imprecise imp)
return sprintf("%g+/-%g",imp)
<span style="color: #008080;">function</span> <span style="color: #000000;">printImprecise</span><span style="color: #0000FF;">(</span><span style="color: #000000;">imprecise</span> <span style="color: #000000;">imp</span><span style="color: #0000FF;">)</span>
end function
<span style="color: #008080;">return</span> <span style="color: #7060A8;">sprintf</span><span style="color: #0000FF;">(</span><span style="color: #008000;">"%g+/-%g"</span><span style="color: #0000FF;">,</span><span style="color: #000000;">imp</span><span style="color: #0000FF;">)</span>
<span style="color: #008080;">end</span> <span style="color: #008080;">function</span>
imprecise x1 = {100, 1.1},
y1 = {50, 1.2},
<span style="color: #000000;">imprecise</span> <span style="color: #000000;">x1</span> <span style="color: #0000FF;">=</span> <span style="color: #0000FF;">{</span><span style="color: #000000;">100</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">1.1</span><span style="color: #0000FF;">},</span>
x2 = {-200, 2.2},
<span style="color: #000000;">y1</span> <span style="color: #0000FF;">=</span> <span style="color: #0000FF;">{</span><span style="color: #000000;">50</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">1.2</span><span style="color: #0000FF;">},</span>
y2 = {-100, 2.3},
<span style="color: #000000;">x2</span> <span style="color: #0000FF;">=</span> <span style="color: #0000FF;">{-</span><span style="color: #000000;">200</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">2.2</span><span style="color: #0000FF;">},</span>
tmp1, tmp2,
<span style="color: #000000;">y2</span> <span style="color: #0000FF;">=</span> <span style="color: #0000FF;">{-</span><span style="color: #000000;">100</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">2.3</span><span style="color: #0000FF;">},</span>
d
<span style="color: #000000;">tmp1</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">tmp2</span><span style="color: #0000FF;">,</span>
<span style="color: #000000;">d</span>
tmp1 = imprecise_add(x1, x2)
tmp1 = imprecise_pow(tmp1, 2)
<span style="color: #000000;">tmp1</span> <span style="color: #0000FF;">=</span> <span style="color: #000000;">imprecise_add</span><span style="color: #0000FF;">(</span><span style="color: #000000;">x1</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">x2</span><span style="color: #0000FF;">)</span>
tmp2 = imprecise_add(y1, y2)
<span style="color: #000000;">tmp1</span> <span style="color: #0000FF;">=</span> <span style="color: #000000;">imprecise_pow</span><span style="color: #0000FF;">(</span><span style="color: #000000;">tmp1</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">2</span><span style="color: #0000FF;">)</span>
tmp2 = imprecise_pow(tmp2, 2)
<span style="color: #000000;">tmp2</span> <span style="color: #0000FF;">=</span> <span style="color: #000000;">imprecise_add</span><span style="color: #0000FF;">(</span><span style="color: #000000;">y1</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">y2</span><span style="color: #0000FF;">)</span>
d = imprecise_add(tmp1,tmp2)
<span style="color: #000000;">tmp2</span> <span style="color: #0000FF;">=</span> <span style="color: #000000;">imprecise_pow</span><span style="color: #0000FF;">(</span><span style="color: #000000;">tmp2</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">2</span><span style="color: #0000FF;">)</span>
d = imprecise_pow(d, 0.5)
<span style="color: #000000;">d</span> <span style="color: #0000FF;">=</span> <span style="color: #000000;">imprecise_add</span><span style="color: #0000FF;">(</span><span style="color: #000000;">tmp1</span><span style="color: #0000FF;">,</span><span style="color: #000000;">tmp2</span><span style="color: #0000FF;">)</span>
printf(1,"Distance, d, between the following points :")
<span style="color: #000000;">d</span> <span style="color: #0000FF;">=</span> <span style="color: #000000;">imprecise_pow</span><span style="color: #0000FF;">(</span><span style="color: #000000;">d</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">0.5</span><span style="color: #0000FF;">)</span>
printf(1,"\n( x1, y1) = ( %s, %s)",{printImprecise(x1),printImprecise(y1)})
<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;">"Distance, d, between the following points :"</span><span style="color: #0000FF;">)</span>
printf(1,"\n( x2, y2) = ( %s, %s)",{printImprecise(x2),printImprecise(y2)})
<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;">"\n( x1, y1) = ( %s, %s)"</span><span style="color: #0000FF;">,{</span><span style="color: #000000;">printImprecise</span><span style="color: #0000FF;">(</span><span style="color: #000000;">x1</span><span style="color: #0000FF;">),</span><span style="color: #000000;">printImprecise</span><span style="color: #0000FF;">(</span><span style="color: #000000;">y1</span><span style="color: #0000FF;">)})</span>
printf(1,"\nis d = %s\n", {printImprecise(d)})</lang>
<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;">"\n( x2, y2) = ( %s, %s)"</span><span style="color: #0000FF;">,{</span><span style="color: #000000;">printImprecise</span><span style="color: #0000FF;">(</span><span style="color: #000000;">x2</span><span style="color: #0000FF;">),</span><span style="color: #000000;">printImprecise</span><span style="color: #0000FF;">(</span><span style="color: #000000;">y2</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;">"\nis d = %s\n"</span><span style="color: #0000FF;">,</span> <span style="color: #0000FF;">{</span><span style="color: #000000;">printImprecise</span><span style="color: #0000FF;">(</span><span style="color: #000000;">d</span><span style="color: #0000FF;">)})</span>
<!--</syntaxhighlight>-->
Aside: obviously you don't ''have'' to use tmp1/2 like that, but I find that style often makes things much easier to debug.
{{out}}
Line 1,952 ⟶ 1,911:
 
The overloaded +, -, * and / operators look a bit complicated, because they must handle an arbitrary number of arguments to be compatible with the standard operators.
<langsyntaxhighlight PicoLisplang="picolisp">(scl 12)
(load "@lib/math.l")
 
Line 2,045 ⟶ 2,004:
(round (car N) 10)
" ± "
(round (sqrt (cdr N) 1.0) 8) ) ) )</langsyntaxhighlight>
Test:
<langsyntaxhighlight PicoLisplang="picolisp">(de distance (X1 Y1 X2 Y2)
(**
(+ (** (- X1 X2) 2.0) (** (- Y1 Y2) 2.0))
Line 2,058 ⟶ 2,017:
(unc 50. 1.2)
(unc 200. 2.2)
(unc 100. 2.3) ) ) )</langsyntaxhighlight>
Output:
<pre>Distance: 111.8033988750 ± 2.48716706</pre>
 
=={{header|Python}}==
<langsyntaxhighlight lang="python">from collections import namedtuple
import math
Line 2,155 ⟶ 2,114:
p1, p2 = (x1, y1), (x2, y2)
print("Distance between points\n p1: %s\n and p2: %s\n = %r" % (
p1, p2, distance(p1, p2)))</langsyntaxhighlight>
 
;Sample output:
Line 2,165 ⟶ 2,124:
=={{header|Racket}}==
{{trans|Mathematica}}
<langsyntaxhighlight lang="racket">#lang racket
 
(struct ± (x dx) #:transparent
Line 2,206 ⟶ 2,165:
(define x2 (± 200 2.2))
(define y2 (± 100 2.3))
(norm (±- x1 x2) (±- y1 y2))</langsyntaxhighlight>
 
{{output}}
Line 2,215 ⟶ 2,174:
{{Works with|rakudo|2018.03}}
{{trans|Perl}}
<syntaxhighlight lang="raku" perl6line># cache of independent sources so we can make them all the same length.
# (Because Raku does not yet have a longest-zip metaoperator.)
my @INDEP;
Line 2,314 ⟶ 2,273:
my $a = $x1 + $x2;
my $b = $y1 - 2 * $x2;
say "covariance between $a and $b: ", covariance($a,$b);</langsyntaxhighlight>
{{out}}
<pre>distance: 111.803±2.49
Line 2,322 ⟶ 2,281:
=={{header|REXX}}==
{{trans|Fortran}}
<langsyntaxhighlight lang="rexx">/*REXX program calculates the distance between two points (2D) with error propagation. */
parse arg a b . /*obtain arguments from the CL*/
if a=='' | a=="," then a= '100±1.1, 50±1.2' /*Not given? Then use default.*/
Line 2,352 ⟶ 2,311:
m.= 9; do j=0 while h>9; m.j= h; h= h%2+1; end /*j*/
do k=j+5 to 0 by -1; numeric digits m.k; g= (g+x/g)*.5; end /*k*/
numeric digits d; return g/1</langsyntaxhighlight>
{{out|output|text=&nbsp; when using the default inputs:}}
<pre>
Line 2,362 ⟶ 2,321:
 
=={{header|Ruby}}==
<langsyntaxhighlight lang="ruby">class NumberWithUncertainty
def initialize(number, error)
@num = number
Line 2,425 ⟶ 2,384:
y2 = NumberWithUncertainty.new(100, 2.3)
 
puts ((x1 - x2) ** 2 + (y1 - y2) ** 2).sqrt</langsyntaxhighlight>
{{out}}
<pre>111.803398874989 ± 2.48716706314634</pre>
Line 2,431 ⟶ 2,390:
=={{header|Scala}}==
{{trans|Kotlin}}
<langsyntaxhighlight lang="scala">import java.lang.Math._
 
class Approx(val ν: Double, val σ: Double = 0.0) {
Line 2,473 ⟶ 2,432:
val y2 = Approx(100.0, 2.3)
println(√(((x1 - x2)^2.0) + ((y1 - y2)^2.0))) // => 111.80339887498948 ±2.938366893361004
}</langsyntaxhighlight>
{{out}}
<pre>111.80339887498948 ±2.938366893361004</pre>
Line 2,479 ⟶ 2,438:
=={{header|Swift}}==
 
<langsyntaxhighlight lang="swift">import Foundation
 
precedencegroup ExponentiationGroup {
Line 2,552 ⟶ 2,511:
let d = ((x2 - x1) ** 2 + (y2 - y1) ** 2) ** 0.5
 
print(d)</langsyntaxhighlight>
 
{{out}}
Line 2,561 ⟶ 2,520:
{{works with|Tcl|8.6}}
Firstly, some support code for doing RAII-like things, evolved from code in the [[Quaternion type#Tcl|quaternion]] solution:
<langsyntaxhighlight lang="tcl">package require Tcl 8.6
oo::class create RAII-support {
constructor {} {
Line 2,614 ⟶ 2,573:
try $script on ok msg {$msg return}
] [uplevel 1 {namespace current}]] {*}$vals
}</langsyntaxhighlight>
The implementation of the number+error class itself:
<langsyntaxhighlight lang="tcl">RAII-class create Err {
variable N E
constructor {number {error 0.0}} {
Line 2,666 ⟶ 2,625:
 
export + - * / **
}</langsyntaxhighlight>
Demonstrating:
<langsyntaxhighlight lang="tcl">set x1 [Err 100 1.1]
set x2 [Err 200 2.2]
set y1 [Err 50 1.2]
Line 2,676 ⟶ 2,635:
[[[$x1 - $x2] ** 2] + [[$y1 - $y2] ** 2]] ** 0.5
}]
puts "d = [$d p]"</langsyntaxhighlight>
Output:
<pre>
Line 2,684 ⟶ 2,643:
=={{header|Wren}}==
{{trans|Kotlin}}
<langsyntaxhighlight ecmascriptlang="wren">class Approx {
construct new(nu, sigma) {
_nu = nu
Line 2,736 ⟶ 2,695:
var x2 = Approx.new(200, 2.2)
var y2 = Approx.new(100, 2.3)
System.print(((x1 - x2).pow(2) + (y1 - y2).pow(2)).pow(0.5))</langsyntaxhighlight>
 
{{out}}
9,476

edits