Task: Pathological floating point problems




Go: package main

import (
    "fmt"
    "math/big"
)

func main() {
    sequence()
    bank()
    rump()
}

func sequence() {
    
    var v, v1 big.Rat
    v1.SetInt64(2)
    v.SetInt64(-4)
    n := 2
    c111 := big.NewRat(111, 1)
    c1130 := big.NewRat(1130, 1)
    c3000 := big.NewRat(3000, 1)
    var t2, t3 big.Rat
    r := func() (vn big.Rat) {
        vn.Add(vn.Sub(c111, t2.Quo(c1130, &v)), t3.Quo(c3000, t3.Mul(&v, &v1)))
        return
    }
    fmt.Println("  n  sequence value")
    for _, x := range []int{3, 4, 5, 6, 7, 8, 20, 30, 50, 100} {
        for ; n < x; n++ {
            v1, v = v, r()
        }
        f, _ := v.Float64()
        fmt.Printf("%3d %19.16f\n", n, f)
    }
}

func bank() {
    
    var balance struct{ e, d big.Int }
    
    balance.e.SetInt64(1)
    balance.d.SetInt64(-1)
    
    var m, one big.Int
    one.SetInt64(1)
    for y := 1; y <= 25; y++ {
        m.SetInt64(int64(y))
        balance.e.Mul(&m, &balance.e)
        balance.d.Mul(&m, &balance.d)
        balance.d.Sub(&balance.d, &one)
    }
    
    var e, ef, df, b big.Float
    e.SetPrec(100).SetString("2.71828182845904523536028747135")
    ef.SetInt(&balance.e)
    df.SetInt(&balance.d)
    b.Add(b.Mul(&e, &ef), &df)
    fmt.Printf("Bank balance after 25 years: $%.2f\n", &b)
}

func rump() {
    a, b := 77617., 33096.
    fmt.Printf("Rump f(%g, %g): %g\n", a, b, f(a, b))
}

func f(a, b float64) float64 {
    
    
    fp := func(x float64) *big.Float { return big.NewFloat(x).SetPrec(128) }
    a1 := fp(a)
    b1 := fp(b)
    a2 := new(big.Float).Mul(a1, a1)
    b2 := new(big.Float).Mul(b1, b1)
    b4 := new(big.Float).Mul(b2, b2)
    b6 := new(big.Float).Mul(b2, b4)
    b8 := new(big.Float).Mul(b4, b4)
    two := fp(2)
    t1 := fp(333.75)
    t1.Mul(t1, b6)
    t21 := fp(11)
    t21.Mul(t21.Mul(t21, a2), b2)
    t23 := fp(121)
    t23.Mul(t23, b4)
    t2 := new(big.Float).Sub(t21, b6)
    t2.Mul(a2, t2.Sub(t2.Sub(t2, t23), two))
    t3 := fp(5.5)
    t3.Mul(t3, b8)
    t4 := new(big.Float).Mul(two, b1)
    t4.Quo(a1, t4)
    s := new(big.Float).Add(t1, t2)
    f64, _ := s.Add(s.Add(s, t3), t4).Float64()
    return f64
}


Java: import java.math.BigDecimal;
import java.math.RoundingMode;

public class FPProblems {
    public static void wrongConvergence() {
        int[] INDEXES = new int[] { 3, 4, 5, 6, 7, 8, 20, 30, 50, 100 };
        
        
        double[] fpValues = new double[100];
        fpValues[0] = 2.0;
        fpValues[1] = -4.0;
        for (int i = 2; i < fpValues.length; i++) {
            fpValues[i] = 111.0 - 1130.0 / fpValues[i - 1] + 3000.0 / (fpValues[i - 1] * fpValues[i - 2]);
        }
        
        
        BigRational[] brValues = new BigRational[100];
        brValues[0] = BigRational.valueOf(2);
        brValues[1] = BigRational.valueOf(-4);
        for (int i = 2; i < brValues.length; i++) {
            
            BigRational clause2 = BigRational.valueOf(1130).divide(brValues[i - 1]);
            BigRational clause3 = BigRational.valueOf(3000).divide(brValues[i - 1].multiply(brValues[i - 2]));
            brValues[i] = BigRational.valueOf(111).subtract(clause2).add(clause3);
        }
        
        System.out.println("Wrong Convergence Sequence");
        for (int n : INDEXES) {
            BigDecimal value = brValues[n - 1].toBigDecimal(16, RoundingMode.HALF_UP);
            System.out.println("  For index " + n + ", FP value is " + fpValues[n - 1] + ", and rounded BigRational value is " + value.toPlainString());
        }
        
        return;
    }
    
    public static void chaoticBankSociety() {
        System.out.println("Chaotic Bank Society");
        double balance = Math.E - 1.0;
        
        
        BigRational e = BigRational.ONE;
        BigRational d = BigRational.ONE;
        for (int i = 1; i < 1000; i++) {
            d = d.multiply(BigRational.valueOf(i));
            e = e.add(d.reciprocal());
        }
        System.out.println("DEBUG: e=" + e.toBigDecimal(100, RoundingMode.HALF_UP).toPlainString());
        
        
        
        
        BigRational brBalance = e.subtract(BigRational.ONE);
        for (int year = 1; year <= 25; year++) {
            balance = (balance * year) - 1.0;
            brBalance = brBalance.multiply(BigRational.valueOf(year)).subtract(BigRational.ONE);
            BigDecimal bdValue = brBalance.toBigDecimal(16, RoundingMode.HALF_UP);
            System.out.println("  Year=" + year + ", FP balance=" + balance + ", BigRational balance=" + bdValue.toPlainString());
        }
    }
    
    public static void siegfriedRump() {
        System.out.println("Siegfried Rump formula");
        double fpValue;
        {
            double a = 77617.0;
            double b = 33096.0;
            fpValue = 333.75 * Math.pow(b, 6) + a * a * (11.0 * a * a * b * b - Math.pow(b, 6) - 121.0 * Math.pow(b, 4) - 2.0) + 5.5 * Math.pow(b, 8) + a / (2.0 * b);
        }
        
        BigRational brValue;
        {
            BigRational a = BigRational.valueOf(77617);
            BigRational b = BigRational.valueOf(33096);
            BigRational clause1 = BigRational.valueOf(333.75).multiply(b.pow(6));
            BigRational clause2a = BigRational.valueOf(11).multiply(a).multiply(a).multiply(b).multiply(b);
            BigRational clause2b = b.pow(6).add(BigRational.valueOf(121).multiply(b.pow(4))).add(BigRational.valueOf(2));
            BigRational clause2 = a.multiply(a).multiply(clause2a.subtract(clause2b));
            BigRational clause3 = BigRational.valueOf(5.5).multiply(b.pow(8));
            BigRational clause4 = a.divide(b.multiply(BigRational.valueOf(2)));
            brValue = clause1.add(clause2).add(clause3).add(clause4);
        }
        
        System.out.println("  FP value is " + fpValue);
        System.out.println("  BigRational rounded value is " + brValue.toBigDecimal(64, RoundingMode.HALF_UP).toPlainString());
        System.out.println("  BigRational full value is " + brValue.toString());
    }
    
    public static void main(String... args) {
        wrongConvergence();
        
        System.out.println();
        chaoticBankSociety();

        System.out.println();
        siegfriedRump();
    }
}