No, truncation is correct in this case. ... as the rounding error seen in my original post was introduced by storing the string representation into a binary float
Whatever works for you.
I am just saying that not all price strings translate into a double that is bigger than the string value, and you will want to make sure that your application doesn't have any situations like the following, for the string "1.13", which has a binary representation slightly less than 1.13 for both double precision and single precision:
C:\usr\local\share\PassThru\perl>perl -le "print int(100*'1.13')"
112
C:\usr\local\share\PassThru\perl>perl -MPOSIX=round -le "print round(1
+00*'1.13')"
113
If your application doesn't have that problem, then great.
However, I still don't see why my suggestion won't work for you. It would be nice for you to show me one example of a price-string to put in $from_api that will not become the right integer number of cents when run through my second section of code:
#### redo, with proper rounding
$from_api = get_from_api();
print "string from_api = '$from_api' straight from api\n";
$from_api .= '.' unless $from_api =~ /\./;
$from_api .= '00';
$from_api =~ s,^(\d+)\.(\d{2})(\d*).*$,${1}${2}.${3},;
print "string from_api = '$from_api' after text manipulation\n";
$from_api = round($from_api);
print "good rounding = ", $from_api, "cents\n";
Here's a testbed, showing that for reasonable strings, our two match. It also shows a couple strange variants, where there's at least one place where your truncation and my rounding come up with different results.
use warnings;
use strict;
use POSIX qw/round/;
use Test::More;
for my $correct_integer_cents ( 0 .. 200 ) {
# first, let's create a testbench using the integer number of cent
+s as the basis
my $price_string = "00" . $correct_integer_cents;
$price_string =~ s/(\d{2})$/.$1/;
my $price_float = $correct_integer_cents / 100;
my $test_name = sprintf "cents=%s str='%s' float='%.15f'", $correc
+t_integer_cents, $price_string, $price_float;
# Now let's compare how your converter and my converter deal with
+these
is anotherguest($price_string), $correct_integer_cents, "anothergu
+est | $test_name";
is pryrt($price_string), $correct_integer_cents, "pryrt
+ | $test_name";
}
# so both are identical for those 201 tests.
# however, what about weird situations
for my $price_string ( '1.13', '1.130000000', 1.13 , sprintf('%.18f',
+1.13) ) {
is anotherguest($price_string), 113, "anotherguest | str='$price_s
+tring'";
is pryrt($price_string), 113, "pryrt | str='$price_s
+tring'";
}
done_testing;
|