Dear Peter,
On Sun, April 13, 2014 1:24 pm, Peter John Acklam via RT wrote:
Show quoted text> Queue: Math-BigInt
> Ticket <URL:
https://rt.cpan.org/Ticket/Display.html?id=72680 >
>
> On Sun Apr 13 06:51:47 2014, nospam-abuse@bloodgate.com wrote:
>>
>> As far as I remember, the idea was that invalid inputs are be NaN (Not a
>> number). I have missed the first part of the bug report, but why should
>> that be changed? What is the alternative?
>
> The idea is good, but the downside is that the semantics are different
> than that of Perl itself, which comes as a surprise to many users.
>
> When Perl converts a string to a number, it parses as much as it can, and
> if there is anything left, it gives a warning:
>
> $ perl -wle 'print 5 + "2.3.4"'
> Argument "2.3.4" isn't numeric in addition (+) at -e line 1.
> 7.3
>
> $ perl -wle 'print 5 + ""'
> Argument "" isn't numeric in addition (+) at -e line 1.
> 5
>
> On the other hand, Math::Big(Int|Flaot) parses the entire string, and
> unless the entire string is a valid number, it returns a "NaN":
>
> $ perl -MMath::BigFloat -wle 'print Math::BigFloat -> new("5") + "2.3.4"'
> NaN
>
> $ perl -MMath::BigFloat -wle 'print Math::BigFloat -> new("5") + ""'
> NaN
>
> Several of the bug reports for the Math::Big(Int|Float) modules are
> related to this difference. People don't expect the semantics of
> Math::Big(Int|Float) to be different than that of core Perl.
Thank you for your explanation, that makes more sense to me. Please let me
expand a bit from the history of the rewrite (and my subsequent
interpretion of the original code of BigInt). Please excuse the lenghty
and late reply.
Short version:
The intention was to make Math::BigInt "correct", and not always replicate
the semantics of Perl. E.g. if you pass something to it that is not
interpretable as an integer or inf, it is NaN.
E.g. anything that is not an integer (or float for BigFloat) SHOULD be a
NaN (or inf as it may be), not silently 0. If one wants the semantics of
Perl, the bignum modules are for it.
Or in other words, Math::BigInt->new( something-not-an-integer ) should
always result in NaN.
I probably muddled the waters by treating undef as special cases, tho,
because that gives the impression it should work for everything you throw
at it. And clearly I never thought about !false and other wierd cases as
my knowledge of Perl was more limited at that time. So some of them might
work by accident.
The reasons for BigInt using NaN and not 0 are manyfold, foremost
consistency:
Perl is quite inconsistent in some places, you can f.i. "increment" 'a',
but not add 1 to to it, and neither can you add "a" to 1:
te@te:$ perl -wle 'my $a = "a"; print $a++'
a
te@te:$ perl -wle 'my $a = "a"; print $a + 1'
Argument "a" isn't numeric in addition (+) at -e line 1.
1
(There is Math::String, which attempts to get it right, but it is rarely
used, I guess)
Likewise differences about undef (which warns or not):
te@te:$ perl -wle 'my $a = undef; print $a + 1'
Use of uninitialized value $a in addition (+) at -e line 1.
1
te@te:$ perl -wle 'my $a = undef; print ++$a'
1
Replicating all these special cases would probably be a nightmare.
Then there is the case of overloading: The magic of adding different
things together works with overloading, but it again causes problems like
that the order of the arguments influences the result:
result = ClassA + ClassB operation is handled by ClassA
result = ClassB + ClassA operation is handled by ClassB
This means that either ClassA and ClassB need to be aware of each other
(which is the model BigInt and BigFloat use, but is quite a big pain) or
the result will differ, which is clearly unexpected in cases like:
result = 1 + 2.5; vs.
result = 2.5 + 1;
Which by extension also means that BigInt needs to know about floats (and
any special case that BigFloat knows about), because it needs to know when
to pass (upgrade) to BigFloat. That makes it more complicated, too.
And there are special cases like:
for ( Math::BigInt->new(1) .. 10 )
which only work in more recent versions of Perl. Frankly, I'm still amazed
that overloading actually works - but I digres :)
Anyway, I've gone to great lenghts to hide BigInt under overloading (and
thus make BigInt appear to work like Perl), but it doesn't always work. So
my idea was to not even attempt it, and only attempt to hide all that away
with "bignum", which adds a few more special cases (and is thus be
slower).
So, my intention was to have it work like this:
Math::BigInt->new( notanumber ) => NaN
-mbignum notanumber + x => NaN
-mbignum specialcase + x => do what Perl does, as much as possible
Now, if the consensus is that this model is rubbish, and
Math::BigInt->new() should do what Perl does, and also be consistent with
bignum, then well, I can't hardly argue against it. But I'd still like to
point out that changing the semantics of Math::BigInt->new() might not be
the best idea or even work 100%.
The argumentation against changing Math::BigInt->new() in some cases is
that you lose the ability to check a string against "being an
integer/number" as opposed to being "interpreted as number by Perl".
So at least it should be thought about what exactly the goal should be.
Here are a few examples where the differences currently show:
Floats:
$ perl -MMath::BigInt -wle 'my $a = Math::BigInt->new(1.5); print $a + 1'
NaN
$ perl -MMath::BigInt -wle 'my $a = Math::BigInt->new(1.5); print $a + 1'
NaN
$ perl -wle 'my $a = 1.5; print $a + 1'
2.5
$ perl -Mbigint -wle 'my $a = 1.5; print $a + 1'
2
$ perl -Mbignum -wle 'my $a = 1.5; print $a + 1'
2.5
And these are oddly enough already consistent (minus the warnings):
undef:
$ perl -MMath::BigInt -wle 'my $a = Math::BigInt->new(undef); print $a + 1'
1
$ perl -wle 'my $a = undef; print $a + 1'
Use of uninitialized value $a in addition (+) at -e line 1.
1
$ perl -Mbigint -wle 'my $a = undef; print $a + 1'
1
$ perl -Mbignum -wle 'my $a = undef; print $a + 1'
1
NaN:
$ perl -MMath::BigInt -wle 'my $a = Math::BigInt->new(NaN); print $a + 1'
NaN
$ perl -wle 'my $a = NaN; print $a + 1'
nan
$ perl -Mbigint -wle 'my $a = NaN; print $a + 1'
NaN
$ perl -Mbignum -wle 'my $a = NaN; print $a + 1'
NaN
inf:
$ perl -MMath::BigInt -wle 'my $a = Math::BigInt->new(inf); print $a + 1'
Unquoted string "inf" may clash with future reserved word at -e line 1.
inf
$ perl -wle 'my $a = inf; print $a + 1'
Unquoted string "inf" may clash with future reserved word at -e line 1.
inf
$ perl -Mbigint -wle 'my $a = inf; print $a + 1'
inf
$ perl -Mbignum -wle 'my $a = inf; print $a + 1'
inf
!false: (here at least bigint and bignum are incorrect IMHO)
$ perl -wle 'my $a = ! (3<5); print $a + 1'
1
$ perl -MMath::BigInt -wle 'my $a=Math::BigInt->new(!(3<5)); print $a + 1'
NaN
$ perl -Mbigint -wle 'my $a = Math::BigInt->new(!(3<5)); print $a + 1'
NaN
$ perl -Mbignum -wle 'my $a = Math::BigInt->new(!(3<5)); print $a + 1'
NaN
Oddly enought, true (as in (3<4) works:
$ perl -wle 'print +(3<4) + 1';
2
$ perl -MMath::BigInt -wle 'print Math::BigInt->new( (3<4) ) + 1';
2
$ perl -Mbigint -wle 'print +(3<4) + 1';
2
$ perl -Mbignum -wle 'print +(3<4) + 1';
2
Here is another special case:
$ perl -MMath::BigInt -wle 'my $a = "++0"; print $a + 1'
Argument "++0" isn't numeric in addition (+) at -e line 1.
1
$ perl -MMath::BigInt -wle 'my $a = Math::BigInt->new("++0"); print $a + 1'
NaN
$ perl -Mbignum -wle 'my $a = "++0"; print $a + 1'
NaN
$ perl -Mbigint -wle 'my $a = "++0"; print $a + 1'
NaN
Again, bigint and bignum should probably handle this case as Perl does
(minus the warning as usual).
(It might be an idea to add the ability to emit all these warnings, but
that is sep. from the discussion about the actual result.)
Another case would be dual-vars:
$ perl -wle 'open (my $i, "<", "foo"); print $! + 1';
3
$ perl -Mbigint -wle 'open (my $i, "<", "foo"); print $! + 1';
NaN
$ perl -Mbignum -wle 'open (my $i, "<", "foo"); print $! + 1';
NaN
$ perl -MMath::BigInt -wle 'open (my $i, "<", "foo"); print
Math::BigInt->new($!) + 1';
NaN
bigint and bignum should print 3, too. But I'm not sure about BigInt. Both
cases could be argued for, afterall, $! is both a string and a number at
the same time. I'd lean towards 3 for BigInt, tho.
Please let me know what you think of that.
Best regards,
Tels
--
http://bloodgate.com/galleries/