Trouble with long integers.

New to FreeBASIC? Post your questions here.
Post Reply
vicgraus
Posts: 2
Joined: Sep 28, 2021 16:02

Trouble with long integers.

Post by vicgraus »

Hi, I'm having trouble with long integers in the -lang qb dialect, which are available with __LONGINT. They don't seem to accept much more than 53 bits (around ±2^52), instead of the claimed 64 bits (±2^63). Perhaps this is an old solved topic, I'm sorry, I haven't found it. See the next program in the -lang qb dialect; it doesn't matter if we use the long integer suffix LL after the numbers (e.g. 52LL) or not, the output is always the same: RIGHT followed by WRONG:

DIM AS __LONGINT X,Y

X=2^52
Y=2^52+1
IF X<>Y THEN PRINT "RIGHT" ELSE PRINT "WRONG"

X=2^53
Y=2^53+1
IF X<>Y THEN PRINT "RIGHT" ELSE PRINT "WRONG"

SLEEP: END

Do we have a bug?
fxm
Moderator
Posts: 12132
Joined: Apr 22, 2009 12:46
Location: Paris suburbs, FRANCE

Re: Trouble with long integers.

Post by fxm »

This behavior is normal and is due to the precision of the conversion: Double -> LongInt, because the Operator ^ returns a Double.
A Double contains at most 53 bits of precision, or about 15 decimal digits.

Works for example with:
X=2^53
Y=2^53+2

Otherwise:

Code: Select all

#lang "qb"

DIM AS __LONGINT X,Y

X=2^53
Y=2^53+1
PRINT X
PRINT Y
IF X<>Y THEN PRINT "RIGHT" ELSE PRINT "WRONG"
PRINT

X=&h20000000000000    '' 2^53
Y=&h20000000000000+1  '' 2^53+1
PRINT X
PRINT Y
IF X<>Y THEN PRINT "RIGHT" ELSE PRINT "WRONG"

SLEEP
dodicat
Posts: 7983
Joined: Jan 10, 2006 20:30
Location: Scotland

Re: Trouble with long integers.

Post by dodicat »

The crt pow function seems a bit more accurate.

Code: Select all

#lang "qb"


declare function pow cdecl alias "pow"(byval as double,byval as double) as double


DIM AS __LONGINT X,Y


X=pow(2,52)
Y=pow(2,52+1)

IF X<>Y THEN PRINT "RIGHT" ELSE PRINT "WRONG"

X=pow(2,53)
Y=pow(2,53+1)
IF X<>Y THEN PRINT "RIGHT" ELSE PRINT "WRONG"

SLEEP: END
 
fxm
Moderator
Posts: 12132
Joined: Apr 22, 2009 12:46
Location: Paris suburbs, FRANCE

Re: Trouble with long integers.

Post by fxm »

Rather 'pow(2,52)+1' and 'pow(2,53)+1', but it still works !
fxm
Moderator
Posts: 12132
Joined: Apr 22, 2009 12:46
Location: Paris suburbs, FRANCE

Re: Trouble with long integers.

Post by fxm »

Works also if returning the exponentiation from a freeBASIC function:

Code: Select all

#lang "qb"


function power(byref a as double,byref b as double) as double
    power=a^b
end function


DIM AS __LONGINT X,Y


X=power(2,52)
Y=power(2,52)+1
Print X
Print Y

IF X<>Y THEN PRINT "RIGHT" ELSE PRINT "WRONG"

X=power(2,53)
Y=power(2,53)+1
Print X
Print Y
IF X<>Y THEN PRINT "RIGHT" ELSE PRINT "WRONG"

SLEEP
 
Also works:
X=2^53
Y=__CAST(__LONGINT,2^53)+1


It all depends on how the Double -> LongInt conversion is done.
badidea
Posts: 2592
Joined: May 24, 2007 22:10
Location: The Netherlands

Re: Trouble with long integers.

Post by badidea »

Use shift left:

Code: Select all

dim as longint X, Y

X = 1ll shl 52 '2^52
Y = 1ll shl 52 + 1 '2^52+1
if X<>Y then print "RIGHT" else print "WRONG"
print Y-X

X = 1ll shl 53 '2^53
Y = 1ll shl 53 + 1 '2^53+1
if X<>Y then print "RIGHT" else print "WRONG"
print Y-X

sleep: end

1ll is needed (in case of 32 bit fbc) to tell the compiler to store 1 as a longint, see: Literal Suffix in Standard Data Type Limits

To further clarify the problem, see compiler output of:

Code: Select all

#print typeof(2 ^ 52)
#print typeof(1ll shl 52)
Which should give for 32 bit fbc:

Code: Select all

DOUBLE
LONGINT
vicgraus
Posts: 2
Joined: Sep 28, 2021 16:02

Re: Trouble with long integers.

Post by vicgraus »

I appreciate all the answers, thanks.
In regard to the answers that use the function POW or POWER, in my platform or version of FreeBasic it just works POWER (not POW), provided that in the POWER definition I substitute __LONGINT for DOUBLE; so for me it works correctly:

#lang "qb"

FUNCTION POWER(BYREF A AS __LONGINT,BYREF B AS __LONGINT) AS __LONGINT
POWER=A^B
END FUNCTION

DIM AS __LONGINT X,Y

X=POWER(2,52)
Y=POWER(2,52)+1
PRINT X
PRINT Y
IF X<>Y THEN PRINT "RIGHT" ELSE PRINT "WRONG"

X=POWER(2,53)
Y=POWER(2,53)+1
PRINT X
PRINT Y
IF X<>Y THEN PRINT "RIGHT" ELSE PRINT "WRONG"

SLEEP: END
Post Reply