Perl / perl5

🐪 The Perl programming language
https://dev.perl.org/perl5/
Other
1.85k stars 527 forks source link

rounding floating numbers by *printf is not good. #1868

Closed p5pRT closed 21 years ago

p5pRT commented 24 years ago

Migrated from rt.perl.org#3134 (status was 'resolved')

Searchable as RT3134$

p5pRT commented 24 years ago

From ts@icu.ac.jp

Created by ts@mojijm.jm.icu.ac.jp

Hi\,

Return value of sprintf( "%2.0f"\, 0.5 ) is 0! But *printf for the value 1.5 works great! Many numbers are also rounded badly. You can play adding some 0's and 1 after 0.5\, say 0.501 or 0.5000000000000001. :}

Cheers\,   -- Shige\, ts@​icu.ac.jp

Perl Info ``` This perlbug was built using Perl 5.00503 - $Date: 1999/05/05 19:42:40 $ It is being executed now by Perl 5.006 - Fri Apr 21 12:09:12 JST 2000. Site configuration information for perl 5.006: Configured by ts at Fri Apr 21 12:09:12 JST 2000. Summary of my perl5 (revision 5.0 version 6 subversion 0) configuration: Platform: osname=freebsd, osvers=3.4-release, archname=i386-freebsd uname='freebsd mojijm.jm.icu.ac.jp 3.4-release freebsd 3.4-release #0: mon dec 20 06:54:39 gmt 1999 jkh@time.cdrom.com:usrsrcsyscompilegeneric i386 ' config_args='-de' hint=recommended, useposix=true, d_sigaction=define usethreads=undef use5005threads=undef useithreads=undef usemultiplicity=undef useperlio=undef d_sfio=undef uselargefiles=define use64bitint=undef use64bitall=undef uselongdouble=undef usesocks=undef Compiler: cc='cc', optimize='-O', gccversion=2.7.2.3 cppflags='-I/usr/local/include' ccflags ='-I/usr/local/include' stdchar='char', d_stdstdio=undef, usevfork=true intsize=4, longsize=4, ptrsize=4, doublesize=8 d_longlong=define, longlongsize=8, d_longdbl=define, longdblsize=12 ivtype='long', ivsize=4, nvtype='double', nvsize=8, Off_t='off_t', lseeksize=8 alignbytes=4, usemymalloc=n, prototype=define Linker and Libraries: ld='cc', ldflags ='-Wl,-E -L/usr/local/lib' libpth=/usr/lib /usr/local/lib libs=-lgdbm -lm -lc -lcrypt libc=/usr/lib/libc.so, so=so, useshrplib=false, libperl=libperl.a Dynamic Linking: dlsrc=dl_dlopen.xs, dlext=so, d_dlsymun=undef, ccdlflags=' ' cccdlflags='-DPIC -fpic', lddlflags='-shared -L/usr/local/lib' Locally applied patches: @INC for perl 5.006: /usr/local/lib/perl5/5.6.0/i386-freebsd /usr/local/lib/perl5/5.6.0 /usr/local/lib/perl5/site_perl/5.6.0/i386-freebsd /usr/local/lib/perl5/site_perl/5.6.0 /usr/local/lib/perl5/site_perl/5.005/i386-freebsd /usr/local/lib/perl5/site_perl/5.005 /usr/local/lib/perl5/site_perl . Environment for perl 5.006: HOME=/home/ts LANG (unset) LANGUAGE (unset) LD_LIBRARY_PATH (unset) LOGDIR (unset) PATH=/home/ts/bin:/bin:/usr/bin:/usr/local/bin:/usr/X11R6/bin:/usr/local/bin:/usr/local/sbin:/usr/X11R6/bin:/usr/local/bin:/usr/local/sbin PERL_BADLANG (unset) SHELL=/usr/local/bin/bash ```
p5pRT commented 24 years ago

From @tamias

On Fri\, Apr 21\, 2000 at 03​:04​:20PM +0900\, TOMITA Shigenari wrote​:

Return value of sprintf( "%2.0f"\, 0.5 ) is 0! But *printf for the value 1.5 works great! Many numbers are also rounded badly. You can play adding some 0's and 1 after 0.5\, say 0.501 or 0.5000000000000001. :}

% perldoc -q round

=head2 Does Perl have a round() function? What about ceil() and floor()? Trig functions?

[...]

Rounding in financial applications can have serious implications\, and the rounding method used should be specified precisely. In these cases\, it probably pays not to trust whichever system rounding is being used by Perl\, but to instead implement the rounding function you need yourself.

To see why\, notice how you'll still have an issue on half-way-point alternation​:

  for ($i = 0; $i \< 1.01; $i += 0.05) { printf "%.1f "\,$i}

  0.0 0.1 0.1 0.2 0.2 0.2 0.3 0.3 0.4 0.4 0.5 0.5 0.6 0.7 0.7   0.8 0.8 0.9 0.9 1.0 1.0

Don't blame Perl. It's the same as in C. IEEE says we have to do this. Perl numbers whose absolute values are integers under 2**31 (on 32 bit machines) will work pretty much like mathematical integers. Other numbers are not guaranteed.

Ronald

p5pRT commented 24 years ago

From @JohnPeacock

On a related topic\, I am putting the finishing touches on a module which will deal with the floating point/rounding issues completely in many normal situations. I have already written and distributed Math​::Currency\, which deals with currency values as integers\, using strict financial style rounding. I have been using it in a production environment for nearly a year now.

I have now (mostly) generalized that to be Math​::FixedPrecision\, which will allow arbitrary precision to be maintained\, without either rounding errors or floating point nonsense (e.g.\, what is 100/9?). I will then turn Math​::Currency into a wrapper and use the Posix Locale data to use the appropriate currency display. I foresee Math​::FixedPrecision to also be useful in scientific situations\, where the result of a calculation should be no more accurate than the least accurate datum.

Watch CPAN for an announcement soon...

John Peacock

____________________Reply Separator____________________ Subject​: Re​: [ID 20000420.006] rounding floating numbers by *printf i Author​: Ronald J Kimball \rjk@&#8203;linguist\.dartmouth\.edu Date​: 4/21/2000 10​:48 AM

On Fri\, Apr 21\, 2000 at 03​:04​:20PM +0900\, TOMITA Shigenari wrote​:

Return value of sprintf( "%2.0f"\, 0.5 ) is 0! But *printf for the value 1.5 works great! Many numbers are also rounded badly. You can play adding some 0's and 1 after 0.5\, say 0.501 or 0.5000000000000001. :}

% perldoc -q round

=head2 Does Perl have a round() function? What about ceil() and floor()? Trig functions?

p5pRT commented 24 years ago

From [Unknown Contact. See original ticket]

Thank you\, Ronald!

NOOOO\, I don't blame Perl! I had no idea to type 'perldoc -q round' at all... X{ I'm really sorry for my poor programing experience. Have a nice day!   -- Shige\, I like Perl & integers.

  Date​: Fri\, 21 Apr 2000 10​:48​:15 -0400   From​: Ronald J Kimball \rjk@&#8203;linguist\.dartmouth\.edu

  On Fri\, Apr 21\, 2000 at 03​:04​:20PM +0900\, TOMITA Shigenari wrote​:

  > Return value of sprintf( "%2.0f"\, 0.5 ) is 0!  
  % perldoc -q round

  Don't blame Perl. It's the same as in C. IEEE says we have to do this.   Perl numbers whose absolute values are integers under 2**31 (on 32 bit   machines) will work pretty much like mathematical integers. Other numbers   are not guaranteed.

  Ronald

p5pRT commented 21 years ago

From @iabyn

not-a-bug

p5pRT commented 21 years ago

@iabyn - Status changed from 'open' to 'resolved'