Hi,
UPDATE: I've now filed a
bug report about this.
I've been chewing on this over the last couple of days, and it doesn't look right to me.
It's an issue that arises only when NV-precision is greater than IV-precision.
So, if ivsize is 8 bytes, then in order to experience the issue, you'll generally need to use a quadmath build (nvtype of __float28, NV-precision of 113 bits).
With such a perl, I get:
C:\_32>perl -wle "$m = (2**113) - 1; $n = 2; print $m % $n;"
0
In contrast, POSIX::fmod returns "1" for the same operation.
C:\_32>perl -MPOSIX -wle "$m = (2**113) - 1; $n = 2; print fmod($m, $n
+);"
1
Here's the section of perlop documentation that I'm looking at:
Binary "%" is the modulo operator, which computes the division remaind
+er
of its first argument with respect to its second argument. Given integ
+er
operands $m and $n: If $n is positive, then "$m % $n" is $m minus the
largest multiple of $n less than or equal to $m. If $n is negative, th
+en
"$m % $n" is $m minus the smallest multiple of $n that is not less tha
+n
$m (that is, the result will be less than or equal to zero). If the
operands $m and $n are floating point values and the absolute value of
$n (that is "abs($n)") is less than "(UV_MAX + 1)", only the integer
portion of $m and $n will be used in the operation (Note: here "UV_MAX
+"
means the maximum of the unsigned integer type). If the absolute value
of the right operand ("abs($n)") is greater than or equal to
"(UV_MAX + 1)", "%" computes the floating-point remainder $r in the
equation "($r = $m - $i*$n)" where $i is a certain integer that makes
+$r
have the same sign as the right operand $n (not as the left operand $m
like C function "fmod()") and the absolute value less than that of $n.
Note that when "use integer" is in scope, "%" gives you direct access
+to
the modulo operator as implemented by your C compiler. This operator i
+s
not as well defined for negative operands, but it will execute faster.
AFAICT, the parts of that documentation that are pertinent to my given example are:
If $n is positive, then "$m % $n" is $m minus the largest multiple of
+$n less than or equal to $m.
....
If the operands $m and $n are floating point values and the absolute v
+alue of
$n (that is "abs($n)") is less than "(UV_MAX + 1)", only the integer
portion of $m and $n will be used in the operation (Note: here "UV_MAX
+"
means the maximum of the unsigned integer type)
And to me that implies that the correct calculation for the given example is to do:
C:\_32>perl -wle "$r = 10384593717069655257060992658440191.0 - (519229
+6858534827628530496329220095.0 * 2); print $r;"
1
This agrees with the value produced by POSIX::fmod(), but disagrees with the value produced by the "%" operator.
Do we agree that perl is buggy here ?
If you have a perl with ivsize of 4, you can also demonstrate the same issue.
With ivsize of 4, NV-precision of 113 bits:
C:\_32>perl -wle "$m = (2**113) - 1; $n = 2; print $m % $n;"
0
C:\_32>perl -MPOSIX -wle "$m = (2**113) - 1; $n = 2; print fmod($m, $n
+);"
1
With ivsize of 4, NV-precision of 64 bits (long double):
C:\>perl -wle "$m = (2**64) - 1; $n = 2; print $m % $n;"
0
C:\>perl -MPOSIX -wle "$m = (2**64) - 1; $n = 2; print fmod($m, $n);"
1
And now to really muddy the waters !!
One might be expecting the trend to continue when ivsize is 4, and NV-precision is 53-bits .... but not so:
C:\_32>perl -wle "$m = (2**53) - 1; $n = 2; print $m % $n;"
1
C:\_32>perl -MPOSIX -wle "$m = (2**53) - 1; $n = 2; print fmod($m, $n)
+;"
1
This time the "%" operator decides to act in accordance with (my reading of) the perlop documentation.
Cheers,
Rob
-
Are you posting in the right place? Check out Where do I post X? to know for sure.
-
Posts may use any of the Perl Monks Approved HTML tags. Currently these include the following:
<code> <a> <b> <big>
<blockquote> <br /> <dd>
<dl> <dt> <em> <font>
<h1> <h2> <h3> <h4>
<h5> <h6> <hr /> <i>
<li> <nbsp> <ol> <p>
<small> <strike> <strong>
<sub> <sup> <table>
<td> <th> <tr> <tt>
<u> <ul>
-
Snippets of code should be wrapped in
<code> tags not
<pre> tags. In fact, <pre>
tags should generally be avoided. If they must
be used, extreme care should be
taken to ensure that their contents do not
have long lines (<70 chars), in order to prevent
horizontal scrolling (and possible janitor
intervention).
-
Want more info? How to link
or How to display code and escape characters
are good places to start.