#!/usr/bin/env perl use strict; use warnings; use Math::BigFloat; use Math::BigInt; use Math::Int128 qw(int128 int128_to_hex); use Math::Int128::die_on_overflow; $\ = $/; # https://www.youtube.com/watch?v=S12qx1DwjVk my $SCALE_BITS = 124; my $SCALE = Math::BigInt->new(2)->bpow($SCALE_BITS); print " Scale: 2**$SCALE_BITS = $SCALE"; sub number2fixed { # Math::Big* --> fixed-pt Math::Int128 return int128( shift->copy->bmul($SCALE)->as_int->bstr ); } sub fixed2number { # fixed-pt Math::Int128 --> Math::BigFloat return scalar Math::BigFloat->new(''.shift)->bdiv($SCALE); } my $EPSILON = fixed2number(int128(1)); print "Epsilon: ", $EPSILON->bstr; print "//// example: Pi"; my $pi1 = Math::BigFloat->bpi(45); print " orig: $pi1"; my $fpi = number2fixed($pi1); print "fixed: ", int128_to_hex($fpi); my $pi2 = fixed2number($fpi); print " conv: $pi2"; # https://www.youtube.com/watch?v=npQF28g6s_k sub mul_fixed { # 2x Math::Int128 --> Math::Int128 return (shift>>($SCALE_BITS/2)) * (shift>>($SCALE_BITS/2)); } print "//// properties of mul_fixed"; print "smallest possible multiplicand: ", fixed2number(int128(1)<<($SCALE_BITS/2)); # demo effect of the smallest possible multiplicand my $mul = number2fixed(Math::BigInt->new(3)); my $toosmall = number2fixed( Math::BigFloat->new("0.000000000000000000216")); print " too small: ", int128_to_hex($toosmall); print "\t* 3 = ", fixed2number(mul_fixed($mul,$toosmall)); my $justenough = number2fixed( Math::BigFloat->new("0.000000000000000000217") ); print "just enough: ", int128_to_hex($justenough); print "\t* 3 = ", fixed2number(mul_fixed($mul,$justenough)); print "//// test case: (45e-10)**2"; my $val = Math::BigFloat->new("0.0000000045"); print " input value: ", $val->bstr; my $fval = number2fixed($val); print " as fixed-pt: ", int128_to_hex($fval); my $p = mul_fixed($fval,$fval); print "fixed-pt mul: ", int128_to_hex($p); print " converted: ", fixed2number($p); print " expected: ", $val->copy->bpow(2);