Re: floating points and sprintf
by pg (Canon) on Nov 14, 2002 at 16:37 UTC
|
| [reply] |
|
|
Do you use the basic blue Perl Monks theme? If so, I'm not surprised you made the error: it's really difficult to tell whether you're logged in or not. This is one of the benefits of using an alternate theme.
This makes it really easy to spot when someone sneaks, for instance, a http://perlmonks.com/ link past you: if you click on it, the site reverts back to the default blue, so you know you can't be logged in.
And of course these days, you're not even limited to the basic flavours, you can either tweak them with CSS inclusions hosted on the site (see your user settings) or either write your own stylesheet or use someone else's (or use someone else's as a basis for bootstrapping your own). This has to be hosted on another machine, but that shouldn't be much of a problem in this day and age.
print@_{sort keys %_},$/if%_=split//,'= & *a?b:e\f/h^h!j+n,o@o;r$s-t%t#u'
| [reply] |
|
|
That explains it completely. I suspected the problem lay inside how I was expecting the float to be evaled by the
perl version of sprintf (given that the int operator will floor() the value). I'll pass the information on to my coworker.
Thanks again.
| [reply] |
Re: floating points and sprintf
by petral (Curate) on Nov 14, 2002 at 18:41 UTC
|
This may not make your co-worker happy, but: $ perl -we'printf"%d, %.0f\n",$a=147.2*100,$a'
14719, 14720
  p | [reply] [d/l] |
Re: floating points and sprintf
by John M. Dlugosz (Monsignor) on Nov 14, 2002 at 15:34 UTC
|
Basically, print $t produces 14720 when sprintf produces 14719.
My guess: printf will round off to get what you expected, while sprintf %d does an int() which simply truncates. If the value were actually 14719.999999999999997, then that would explain the difference.
Note that floating point binary can't hold 1/10 exactly any more than decimal can hold 1/3 exactly.
Try using %.15f on such a value and see closer too what's really stored. | [reply] |
|
|
Check my just posted note. The real value is 147.2. That
is mulitplied by 100 (value should be close to 14720.0) and then converted. I understand rounding errors converting from floats to ints but this problem strikes me as a bug.
| [reply] |
|
|
| [reply] [d/l] |
Re: floating points and sprintf
by Anonymous Monk on Nov 14, 2002 at 16:34 UTC
|
As Perl is based on c, let's look at how c handles this. In c, you can do:
float x = 147.2;
printf("%20.20f", x * 100);
it gives you 14719.99969482421875000000, which is fine, unless you are working on some finance application (COBOL will not have this problem, as its decimal is fixed; In Java you will have same thing as c, as Java is also c based, just like Perl, but Java has a class called BigDecimal, which holds fixed decimal.)
However, when you try
float x = 147.2;
printf("%d", x * 100);
It produces -167772160, which is garbage, but it is not a c problem, it is the programmer's problem, as c is trying to interprete that piece of memory as integer, as the programmer required.
To resolve this problem, when they develop Perl, they did this:
float x = 147.2;
printf("%d", (int)(x * 100));
which prints out 14719.
So a new problem is introduced. However this would be fine to most people, most of the time. If you really care the accuracy and precision, because of the nature of your application, then try Math::BigFloat.
| [reply] [d/l] [select] |
|
|
I digged a little bit. Try this, go module Math::BigFloat, there is a function called norm, add one line at the end of this sub "print $_;". You will see how it stores the float as a string, and also its precision.
| [reply] |
Re: floating points and sprintf
by Zaxo (Archbishop) on Nov 14, 2002 at 15:31 UTC
|
Wrong format, he wants '%e' or '%f'.
Oops, replied to the title. Decimal representation of binary fractions problen, see 'perldoc -q round' from perlfaq4..
After Compline, Zaxo
| [reply] |
|
|
Not if he wants to convert a float to an int (check my quote
from the perlfunc document). I forgot to include a table of results. Here it is:
$ ./chksprintf.pl
147 14700 14700 14700
147.1 14710 14710 14710
147.2 14720 14720 14719
147.3 14730 14730 14730
147.4 14740 14740 14740
| [reply] |