tasks a-s

This commit is contained in:
Ingy döt Net 2013-04-10 23:57:08 -07:00
parent 47bf37c096
commit b83f433714
12433 changed files with 156208 additions and 123 deletions

View file

@ -0,0 +1,8 @@
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.
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.
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.
===Task===
Show how +↓ and +↑ 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'' +↓ ''b'', ''a'' +↑ ''b''].

View file

@ -0,0 +1,2 @@
---
note: Arithmetic operations

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,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,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,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,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,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 1000 digits. */
y=digits() /*sets Y to existing number of digits.*/
numeric digits digits()+digits()%10 /*increase digits by 10%.*/

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,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]]
}