Task: Numeric error propagation




Go: package main

import (
    "fmt"
    "math"
)




type unc struct {
    n float64 
    s float64 
}


func newUnc(n, s float64) *unc {
    return &unc{n, s * s}
}



func (z *unc) errorTerm() float64 {
    return math.Sqrt(z.s)
}









func (z *unc) addC(a *unc, c float64) *unc {
    *z = *a
    z.n += c
    return z
}

func (z *unc) subC(a *unc, c float64) *unc {
    *z = *a
    z.n -= c
    return z
}

func (z *unc) addU(a, b *unc) *unc {
    z.n = a.n + b.n
    z.s = a.s + b.s
    return z
}
func (z *unc) subU(a, b *unc) *unc {
    z.n = a.n - b.n
    z.s = a.s + b.s
    return z
}


func (z *unc) mulC(a *unc, c float64) *unc {
    z.n = a.n * c
    z.s = a.s * c * c
    return z
}

func (z *unc) divC(a *unc, c float64) *unc {
    z.n = a.n / c
    z.s = a.s / (c * c)
    return z
}

func (z *unc) mulU(a, b *unc) *unc {
    prod := a.n * b.n
    z.n, z.s = prod, prod*prod*(a.s/(a.n*a.n)+b.s/(b.n*b.n))
    return z
}

func (z *unc) divU(a, b *unc) *unc {
    quot := a.n / b.n
    z.n, z.s = quot, quot*quot*(a.s/(a.n*a.n)+b.s/(b.n*b.n))
    return z
}


func (z *unc) expC(a *unc, c float64) *unc {
    f := math.Pow(a.n, c)
    g := f * c / a.n
    z.n = f
    z.s = a.s * g * g
    return z
}

func main() {
    x1 := newUnc(100, 1.1)
    x2 := newUnc(200, 2.2)
    y1 := newUnc(50, 1.2)
    y2 := newUnc(100, 2.3)
    var d, d2 unc
    d.expC(d.addU(d.expC(d.subU(x1, x2), 2), d2.expC(d2.subU(y1, y2), 2)), .5)
    fmt.Println("d:    ", d.n)
    fmt.Println("error:", d.errorTerm())
}


Java: public class Approx {
    private double value;
    private double error;
    
    public Approx(){this.value = this.error = 0;}
    
    public Approx(Approx b){
        this.value = b.value;
        this.error = b.error;
    }
    
    public Approx(double value, double error){
        this.value = value;
        this.error = error;
    }
    
    public Approx add(Approx b){
        value+= b.value;
        error = Math.sqrt(error * error + b.error * b.error);
        return this;
    }
    
    public Approx add(double b){
        value+= b;
        return this;
    }
    
    public Approx sub(Approx b){
        value-= b.value;
        error = Math.sqrt(error * error + b.error * b.error);
        return this;
    }
    
    public Approx sub(double b){
        value-= b;
        return this;
    }
    
    public Approx mult(Approx b){
        double oldVal = value;
        value*= b.value;
        error = Math.sqrt(value * value * (error*error) / (oldVal*oldVal) +
                                  (b.error*b.error) / (b.value*b.value));
        return this;
    }

    public Approx mult(double b){
        value*= b;
        error = Math.abs(b * error);
        return this;
    }
    
    public Approx div(Approx b){
        double oldVal = value;
        value/= b.value;
        error = Math.sqrt(value * value * (error*error) / (oldVal*oldVal) +
                                  (b.error*b.error) / (b.value*b.value));
        return this;
    }

    public Approx div(double b){
        value/= b;
        error = Math.abs(b * error);
        return this;
    }
    
    public Approx pow(double b){
        double oldVal = value;
        value = Math.pow(value, b);
        error = Math.abs(value * b * (error / oldVal));
        return this;
    }
    
    @Override
    public String toString(){return value+"±"+error;}
    
    public static void main(String[] args){
        Approx x1 = new Approx(100, 1.1);
        Approx y1 = new Approx(50, 1.2);
        Approx x2 = new Approx(200, 2.2);
        Approx y2 = new Approx(100, 2.3);
        
        x1.sub(x2).pow(2).add(y1.sub(y2).pow(2)).pow(0.5);
        
        System.out.println(x1);
    }
}