Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Math::BigFloat - bug giving NaN on multiplying 1 * 1e-05 #15098

Closed
p5pRT opened this issue Dec 18, 2015 · 10 comments
Closed

Math::BigFloat - bug giving NaN on multiplying 1 * 1e-05 #15098

p5pRT opened this issue Dec 18, 2015 · 10 comments

Comments

@p5pRT
Copy link

p5pRT commented Dec 18, 2015

Migrated from rt.perl.org#126960 (status was 'rejected')

Searchable as RT126960$

@p5pRT
Copy link
Author

p5pRT commented Dec 18, 2015

From @epa

Created by @epa

Please see the following test program​:

use Math​::BigFloat;
foreach my $use_bigfloat (0, 1) {
  my $x;
  if ($use_bigfloat) {
  print "using BigFloat, ";
  $x = Math​::BigFloat->new(1);
  }
  else {
  print "using ordinary scalar, ";
  $x = 1;
  }
  print "x=$x\n";
  foreach my $t (0.0001, 0.00001) {
  print "t=$t\n";
  my $p = $x + $t;
  print "p=$p\n";
  my $i = int($p);
  print "i=$i\n";
  my $m = $t * $i;
  print "m=$m\n";
  print "\n";
  }
  print "\n";
}

For me this prints the following​:

using ordinary scalar, x=1
t=0.0001
p=1.0001
i=1
m=0.0001

t=1e-05
p=1.00001
i=1
m=1e-05

using BigFloat, x=1
t=0.0001
p=1.0001
i=1
m=0

t=1e-05
p=1.00001
i=1
m=NaN

I can see no reason why in the last section 1e-05 * 1 should give NaN.

Perl Info

Flags:
    category=library
    severity=high
    module=Math::BigFloat

Site configuration information for perl 5.22.1:

Configured by Red Hat, Inc. at Mon Dec 14 11:14:02 UTC 2015.

Summary of my perl5 (revision 5 version 22 subversion 1) configuration:
   
  Platform:
    osname=linux, osvers=4.3.0-1.fc24.x86_64, archname=x86_64-linux-thread-multi
    uname='linux buildvm-04-nfs.phx2.fedoraproject.org 4.3.0-1.fc24.x86_64 #1 smp mon nov 2 16:27:20 utc 2015 x86_64 x86_64 x86_64 gnulinux '
    config_args='-des -Doptimize=none -Dccflags=-O2 -g -pipe -Wall -Werror=format-security -Wp,-D_FORTIFY_SOURCE=2 -fexceptions -fstack-protector-strong --param=ssp-buffer-size=4 -grecord-gcc-switches  -m64 -mtune=generic -Dldflags=-Wl,-z,relro  -Dccdlflags=-Wl,--enable-new-dtags -Wl,-z,relro  -Dlddlflags=-shared -Wl,-z,relro  -Dshrpdir=/usr/lib64 -DDEBUGGING=-g -Dversion=5.22.1 -Dmyhostname=localhost -Dperladmin=root@localhost -Dcc=gcc -Dcf_by=Red Hat, Inc. -Dprefix=/usr -Dvendorprefix=/usr -Dsiteprefix=/usr/local -Dsitelib=/usr/local/share/perl5 -Dsitearch=/usr/local/lib64/perl5 -Dprivlib=/usr/share/perl5 -Dvendorlib=/usr/share/perl5/vendor_perl -Darchlib=/usr/lib64/perl5 -Dvendorarch=/usr/lib64/perl5/vendor_perl -Darchname=x86_64-linux-thread-multi -Dlibpth=/usr/local/lib64 /lib64 /usr/lib64 -Duseshrplib -Dusethreads -Duseithreads -Dusedtrace=/usr/bin/dtrace -Duselargefiles -Dd_semctl_semun -Di_db -Ui_ndbm -Di_gdbm -Di_shadow -Di_syslog -Dman3ext=3pm -Duseperlio -Dinstallusrbinperl=n -Ubincompat5005 -Uversiononly -Dpager=/usr/bin/less -isr -Dd_gethostent_r_proto -Ud_endhostent_r_proto -Ud_sethostent_r_proto -Ud_endprotoent_r_proto -Ud_setprotoent_r_proto -Ud_endservent_r_proto -Ud_setservent_r_proto -Dscriptdir=/usr/bin -Dusesitecustomize'
    hint=recommended, useposix=true, d_sigaction=define
    useithreads=define, usemultiplicity=define
    use64bitint=define, use64bitall=define, uselongdouble=undef
    usemymalloc=n, bincompat5005=undef
  Compiler:
    cc='gcc', ccflags ='-D_REENTRANT -D_GNU_SOURCE -O2 -g -pipe -Wall -Werror=format-security -Wp,-D_FORTIFY_SOURCE=2 -fexceptions -fstack-protector-strong --param=ssp-buffer-size=4 -grecord-gcc-switches -m64 -mtune=generic -fwrapv -fno-strict-aliasing -I/usr/local/include -D_LARGEFILE_SOURCE -D_FILE_OFFSET_BITS=64',
    optimize='  -g',
    cppflags='-D_REENTRANT -D_GNU_SOURCE -O2 -g -pipe -Wall -Werror=format-security -Wp,-D_FORTIFY_SOURCE=2 -fexceptions -fstack-protector-strong --param=ssp-buffer-size=4 -grecord-gcc-switches -m64 -mtune=generic -fwrapv -fno-strict-aliasing -I/usr/local/include'
    ccversion='', gccversion='5.3.1 20151207 (Red Hat 5.3.1-2)', gccosandvers=''
    intsize=4, longsize=8, ptrsize=8, doublesize=8, byteorder=12345678, doublekind=3
    d_longlong=define, longlongsize=8, d_longdbl=define, longdblsize=16, longdblkind=3
    ivtype='long', ivsize=8, nvtype='double', nvsize=8, Off_t='off_t', lseeksize=8
    alignbytes=8, prototype=define
  Linker and Libraries:
    ld='gcc', ldflags ='-Wl,-z,relro  -fstack-protector-strong -L/usr/local/lib'
    libpth=/usr/local/lib64 /lib64 /usr/lib64 /usr/local/lib /usr/lib /lib/../lib64 /usr/lib/../lib64 /lib
    libs=-lpthread -lresolv -lnsl -lgdbm -ldb -ldl -lm -lcrypt -lutil -lc -lgdbm_compat
    perllibs=-lpthread -lresolv -lnsl -ldl -lm -lcrypt -lutil -lc
    libc=libc-2.22.so, so=so, useshrplib=true, libperl=libperl.so
    gnulibc_version='2.22'
  Dynamic Linking:
    dlsrc=dl_dlopen.xs, dlext=so, d_dlsymun=undef, ccdlflags='-Wl,--enable-new-dtags -Wl,-z,relro '
    cccdlflags='-fPIC', lddlflags='-shared -Wl,-z,relro  -L/usr/local/lib -fstack-protector-strong'

Locally applied patches:
    Fedora Patch1: Removes date check, Fedora/RHEL specific
    Fedora Patch3: support for libdir64
    Fedora Patch4: use libresolv instead of libbind
    Fedora Patch5: USE_MM_LD_RUN_PATH
    Fedora Patch6: Skip hostname tests, due to builders not being network capable
    Fedora Patch7: Dont run one io test due to random builder failures
    Fedora Patch15: Define SONAME for libperl.so
    Fedora Patch16: Install libperl.so to -Dshrpdir value
    Fedora Patch22: Document Math::BigInt::CalcEmu requires Math::BigInt (CPAN RT#85015)
    Fedora Patch26: Make *DBM_File desctructors thread-safe (RT#61912)
    Fedora Patch27: Make PadlistNAMES() lvalue again (CPAN RT#101063)
    Fedora Patch28: Make magic vtable writable as a work-around for Coro (CPAN RT#101063)
    Fedora Patch200: Link XS modules to libperl.so with EU::CBuilder on Linux
    Fedora Patch201: Link XS modules to libperl.so with EU::MM on Linux


@INC for perl 5.22.1:
    /usr/local/lib64/perl5
    /usr/local/share/perl5
    /usr/lib64/perl5/vendor_perl
    /usr/share/perl5/vendor_perl
    /usr/lib64/perl5
    /usr/share/perl5
    .


Environment for perl 5.22.1:
    HOME=/home/eda
    LANG=en_GB.UTF-8
    LANGUAGE (unset)
    LC_COLLATE=C
    LC_CTYPE=en_GB.UTF-8
    LC_MESSAGES=en_GB.UTF-8
    LC_MONETARY=en_GB.UTF-8
    LC_NUMERIC=en_GB.UTF-8
    LC_TIME=en_GB.UTF-8
    LD_LIBRARY_PATH (unset)
    LOGDIR (unset)
    PATH=/home/eda/bin:/usr/local/bin:/usr/bin:/usr/local/sbin:/usr/sbin:/home/eda/.local/bin:/home/eda/bin:/sbin:/usr/sbin
    PERL_BADLANG (unset)
    SHELL=/bin/bash

Please ignore autogenerated disclaimer below this point.

This email is intended only for the person to whom it is addressed and may contain confidential information. Any retransmission, copying, disclosure or other use of, this information by persons other than the intended recipient is prohibited. If you received this email in error, please contact the sender and delete the material. This email is for information only and is not intended as an offer or solicitation for the purchase or sale of any financial instrument. Wadhwani Asset Management LLP is a Limited Liability Partnership registered in England (OC303168) with registered office at 40 Berkeley Square, 3rd Floor, London, W1J 5AL. It is authorised and regulated by the Financial Conduct Authority.

@p5pRT
Copy link
Author

p5pRT commented Dec 20, 2015

From @pjacklam

This behaviour is as documented and as intended. Whether this is the most
sensible behaviour is debatable, but it is at least as it works now.

If we go to the core of what creates the NaN​:
​​
$x = Math​::BigFloat->new(1); # $x is a Math​::BigFloat
$t = 0.00001; # $t is a scalar
$p = $x + $t; # $p is a Math​::BigFloat
$i = int($p); # $i is a Math​::BigInt
$m = $t * $i; # $m is a Math​::BigInt

You see, your call to int() creates a Math​::BigInt. Multiplying 0.00001, or
any other non-integer, with a Math​::BigInt creates a NaN, because a
non-integer can't be represented as a Math​::BigInt.

You can get around this in several ways. One is to use the following at the
top of your program​:

use Math​::BigFloat;
use Math​::BigInt upgrade => 'Math​::BigFloat';

A second way is to use "$i = $p->bint();" rather than "$i = int($p)".

A third way is to use "$t = Math​::BigFloat->new("0.00001");" rather than
letting $t be a scalar.

I hope this helps.

Peter

@p5pRT
Copy link
Author

p5pRT commented Dec 20, 2015

The RT System itself - Status changed from 'new' to 'open'

@p5pRT
Copy link
Author

p5pRT commented Dec 20, 2015

From @epa

But why do 0.0001 and 0.00001 behave differently? That cannot be right.

On 20 Dec 2015, at 14​:15, Peter John Acklam <pjacklam@​gmail.com<mailto​:pjacklam@​gmail.com>> wrote​:

This behaviour is as documented and as intended. Whether this is the most sensible behaviour is debatable, but it is at least as it works now.

If we go to the core of what creates the NaN​:
​​
$x = Math​::BigFloat->new(1); # $x is a Math​::BigFloat
$t = 0.00001; # $t is a scalar
$p = $x + $t; # $p is a Math​::BigFloat
$i = int($p); # $i is a Math​::BigInt
$m = $t * $i; # $m is a Math​::BigInt

You see, your call to int() creates a Math​::BigInt. Multiplying 0.00001, or any other non-integer, with a Math​::BigInt creates a NaN, because a non-integer can't be represented as a Math​::BigInt.

You can get around this in several ways. One is to use the following at the top of your program​:

use Math​::BigFloat;
use Math​::BigInt upgrade => 'Math​::BigFloat';

A second way is to use "$i = $p->bint();" rather than "$i = int($p)".

A third way is to use "$t = Math​::BigFloat->new("0.00001");" rather than letting $t be a scalar.

I hope this helps.

Peter

______________________________________________________________________
This email has been scanned by the Symantec Email Security.cloud service.
For more information please visit http​://www.symanteccloud.com
______________________________________________________________________

This email is intended only for the person to whom it is addressed and may contain confidential information. Any retransmission, copying, disclosure or other use of, this information by persons other than the intended recipient is prohibited. If you received this email in error, please contact the sender and delete the material. This email is for information only and is not intended as an offer or solicitation for the purchase or sale of any financial instrument. Wadhwani Asset Management LLP is a Limited Liability Partnership registered in England (OC303168) with registered office at 40 Berkeley Square, 3rd Floor, London, W1J 5AL. It is authorised and regulated by the Financial Conduct Authority.

@p5pRT
Copy link
Author

p5pRT commented Dec 20, 2015

From @pjacklam

eda@​waniasset.com​:

But why do 0.0001 and 0.00001 behave differently? That cannot be right.

Sorry for not noticing the different results. When I ran your code, I got NaN in both cases. When I ran your code with an older version of the Math-BigInt distribution (which contains the Math​::BigFloat module), I was able to reproduce your result. It turns out that this is a bug that was fixed in version 1.999701 of the Math-BigInt distribution. It was released in Septeber this year. In earlier versions, Math​::BigInt converted all non-integer values to NaNs EXCEPT numbers in the range -1 < x < 1 that were written as decimal numbers, i.e., as "0.0001", not "1e-4"​:

So the reason for the different behaviour in the two cases is that the two numbers stringify differently​: The number 0.0001 becomes the string "0.0001", but 0.00001 becomes the string "1e-5". That difference is essential. The first case hits the bug, but the second doesn't. You can actually see you get m=0 in both cases if you change your code to

  foreach my $t ("0.0001", "0.00001") {

and you get NaN in both cases if you change your code to

  foreach my $t ("1e-4", "1e-5") {

In any case, this is a bug that has been fixed, so I suggest you upgrade to Math-BigInt version 1.999701 or newer.

As a friendly reminder, please include the version number of relevant modules, if you submit another Perl bug report. It just makes life a little bit easier for the developers. :-)

Cheers,
Peter

@p5pRT
Copy link
Author

p5pRT commented Dec 21, 2015

From @epa

Thanks for the explanation. Can the newer version of Math​::BigFloat be added
to the next Perl stable release (5.22.2)? If so this bug can be changed to
PENDING_RELEASE.

--
Ed Avis <eda@​waniasset.com>

@p5pRT
Copy link
Author

p5pRT commented Dec 21, 2015

From @pjacklam

ma. 21. des. 2015 01.46.23 skrev eda@​waniasset.com​:

Thanks for the explanation. Can the newer version of Math​::BigFloat
be added to the next Perl stable release (5.22.2)? If so this bug
can be changed to PENDING_RELEASE.

I don't know about 5.22.2, but 5.23.5 contains the most recent
version of Math​::BigFloat.

@p5pRT
Copy link
Author

p5pRT commented Dec 21, 2015

From @epa

OK, so this will be fixed in perl 5.24 and so can be PENDING_RELEASE.
It will be up to the stable series pumpking (if such a post exists) whether
to include the new Math​::BigFloat in 5.22.2.

--
Ed Avis <eda@​waniasset.com>

@p5pRT
Copy link
Author

p5pRT commented Dec 22, 2015

From @tonycoz

On Mon Dec 21 06​:15​:08 2015, eda@​waniasset.com wrote​:

OK, so this will be fixed in perl 5.24 and so can be PENDING_RELEASE.
It will be up to the stable series pumpking (if such a post exists) whether
to include the new Math​::BigFloat in 5.22.2.

The Math​::Big* modules are now CPAN upstream, so closing this ticket.

Tony

@p5pRT
Copy link
Author

p5pRT commented Dec 22, 2015

@tonycoz - Status changed from 'open' to 'rejected'

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

1 participant