[GiNaC-list] Possible size issue in test in numeric.cpp
Richard B. Kreckel
kreckel at ginac.de
Wed Aug 16 23:13:51 CEST 2006
Hi!
Jens Vollinga wrote:
> Pierangelo Masarati schrieb:
>
>> Jens Vollinga writes:
>>
>>> @Richy:
>>> You wondered why the other ctor for unsigned int doesn't raise such
>>> a warning. After looking at the code I now wonder whether the code
>>> there is optimal. The argument is compared against
>>> 2^(cl_value_len-1) and not 2^(cl_value_len)-1 as one might expect.
>>> Maybe this should be changed? Could you comment on this soon,
>>> because I'd like to roll the release this evening?
>>
>>
>> I agree it should be
>> i < ((1UL << cl_value_len)-1)
>
>
> well, I have to correct myself: it should be
> i < (1UL << cl_value_len)
> I guess.
>
>> In this case, a fix similar to the "int" case on 64 bit architectires
>> would apply, since a "unsigned" will always be less than 2^32. A
>> patch is available at
>> <http://mbdyn.aero.polimi.it/~masarati/Download/mbdyn/ginac-numeric-uint.pat
>> ch>
>
>
> thanks, but I've already done that :-)
>
> But still I want to wait for Richy's response before I put it in CVS,
> because it could be that CLN uses a signed data representation for
> small integers internally (crazy idea, but conceivable ... ;-)) so
> that the original if clause might be correct.
For small integers, CLN uses immediate types (no heap allocation). They
occupy cl_value_len bits. (Not all bits inside a word can be used,
because some bits must be reserved for tagging heap-allocated objects.)
Now, these integers of cl_value_len bits are signed:
2^(cl_value_len-1)...2^(cl_value_len-1)-1. The GiNaC code we are
discussing uses different ctors, one from int and one from unsigned int,
which both result in the same immediate type. There is no unsigned
immediate type! For large numbers it must use some ctor that is not
prone to rollover errors. (For reasons of performance, such rollover
errors were deemed acceptable in CLN for int types, since when coding
with ints, one has to be aware of these rollover errors anyway. In
GiNaC, I didn't want to incur such behavior. Hence, the if statement.)
The current code is correct.
In the ctor from int, we can test that the undesired rollover starts at
(1L << (cl_value_len-1)) and below -(1L << (cl_value_len-1))). Actual
numbers are from a 32-bit system where cl_value_len is 30. They might be
different on other machines.
int i;
cl_I X;
i = (1L << (cl_value_len-1));
X = i;
cout << i << " and " << X << endl; // bad: 536870912 and -536870912
i = i - 1;
X = i;
cout << i << " and " << X << endl; // good: 536870911 and 536870911
i = -(1L << (cl_value_len-1));
X = i;
cout << i << " and " << X << endl; // good: -536870912 and -536870912
i = i - 1;
X = i;
cout << i << " and " << X << endl; // bad: -536870913 and 536870911
In the ctor from unsigned, we can verify that the undesired rollover is
at the same point:
unsigned i;
cl_I X;
i = (1UL << (cl_value_len-1));
X = i;
cout << i << " and " << X << endl; // bad: 536870912 and -536870912
i = i - 1;
X = i;
cout << i << " and " << X << endl; // good: 536870911 and 536870911
Now, you seem to be suggesting to test against twice that value, i <
(1UL << cl_value_len). This is going to lead to undesired behavior:
unsigned i;
cl_I X;
i = (1UL << cl_value_len) - 1;
X = i;
cout << i << " and " << X << endl; // bad: 1073741823 and -1
HTH
-richy.
--
Richard B. Kreckel
<http://www.ginac.de/~kreckel/>
More information about the GiNaC-list
mailing list