#!perl use 5.012; # strict, // use warnings; use Machine::Epsilon; use Data::IEEE754::Tools qw/ulp/; use Test::More; sub dprint { my ($name, $value) = @_; diag sprintf '%-16s => %24.17e', $name, $value } my $eps = machine_epsilon(); # note the docs say that it's relative, _not_ absolute my $ulp1 = ulp(1); # ULP = https://en.wikipedia.org/wiki/Unit_in_the_last_place is $eps, $ulp1, 'machine epsilon is same as ULP(1)'; dprint eps => $eps; dprint 'ulp(1)' => $ulp1; isnt $eps, ulp(2), 'machine epsilon is not same as ULP(2)'; dprint 'ulp(2)'=> ulp(2); is $eps*2, ulp(2), 'machine epsilon scaled by 2 is actually the same as ULP(2)'; dprint '2*eps', 2*$eps; isnt $eps*2.1, ulp(2.1), 'machine epsilon is _not_ scaled by 2.1 to give the same as ULP(2)'; dprint '2.1*eps', 2.1*$eps; dprint 'ulp(2.1)' => ulp(2.1); isnt $eps, ulp(1/10), 'machine epsilon is not the same as ULP(1/10)'; dprint 'ulp(1/10)', ulp(1/10); diag 'using machine epsilon does not give the results you seem to think'; my $start = 1e5; my $x = $start; $x -= (1/10) for 1..1e6; # one million subtractions of 0.1 my $diff = $start - 1e6*(1/10); # subtract one million times the floating point 0.1 isnt $x, $diff, '1 million single steps is not the same as removing one million times the step-value'; dprint 'x' => $x; dprint 'diff' => $diff; my $sectokia = $x + 2*$eps; # this is the fix that sectokia applied isnt $sectokia, $diff; dprint 'sectokia' => $sectokia; diag "stringify sectokia = ".($sectokia)."\n"; diag "in case you don't believe mine is equivalent:"; $start = 0.8; $_ = 0; $x = $start; $sectokia = $x + 2*$eps; # this is adding the two epsilons... $diff = $start - $_ * 0.01; diag sprintf "loop %4d:\n\tx = %24.17e = '%s',\n\tsectokia = %24.17e = '%s',\n\tdiff = %24.17e = '%s'", $_, $x, $x, $sectokia, $sectokia, $diff, $diff; for (1..1000) { $x -= 0.01; # same as your $x -= 0.01 in the for loop $sectokia = $x + 2*$eps; # this is adding the two epsilons... $diff = $start - $_ * 0.01; if( $_ < 10 or 0 == $_ % 100 ) { diag sprintf "loop %4d:\n\tx = %24.17e = '%s',\n\tsectokia = %24.17e = '%s',\n\tdiff = %24.17e = '%s'", $_, $x, $x, $sectokia, $sectokia, $diff, $diff; } if( "$sectokia" ne "$diff" ) { # if the stringified diag sprintf "loop %4d:\n\tx = %24.17e = '%s',\n\tsectokia = %24.17e = '%s',\n\tdiff = %24.17e = '%s'", $_, $x, $x, $sectokia, $sectokia, $diff, $diff; diag "mismatch ends loop at $_\n\n"; last; } } done_testing;