Always for me a Big question

New to FreeBASIC? Post your questions here.
student1347
Posts: 49
Joined: Dec 16, 2011 3:48

Always for me a Big question

With all the progresses in computer science and in year 2017 why programs can keep only 20-digit numbers(ulongint) and if I want to compute long and big numbers there is a limitation in it? In freebasic we can have a string about 2G it is good ,but with numbers......? I want to work with big numbers about for example 500 digits and can I have a digit unit other than binary or decade with ascci codes(base 256 ) and how ?
Last edited by student1347 on May 05, 2017 11:53, edited 1 time in total.
MrSwiss
Posts: 3665
Joined: Jun 02, 2013 9:27
Location: Switzerland

Re: Always for me a Big question

There are libraries for that very purpose (I am not aware of any language, having such *native*).
See: Section Library's of the Forum ...
dodicat
Posts: 6766
Joined: Jan 10, 2006 20:30
Location: Scotland

Re: Always for me a Big question

get the gmp library.
gmp 6.1.2
from srvaldez (top post)
http://www.freebasic.net/forum/viewtopic.php?f=3&t=24110&p=230255#p230255

Put the static library (.a) into your lib folder.
That's all.
Try this factorial.

Code: Select all

#Include Once "gmp.bi"

Function factorial(n As Ulong,numberbase as long=10) As String
Dim As ZString Ptr s = mpz_get_str(0, numberbase, @intanswer)
function= Trim(*s)
deallocate(s)
End Function

print factorial(150,16)
print
print factorial(150,10)
sleep

srvaldez
Posts: 2578
Joined: Sep 25, 2005 21:54

Re: Always for me a Big question

hello student1347
you may also be interested in the "Big Number Wrapper" (using GMP int) by Yetifoot viewtopic.php?t=7173
example code by Yetifoot

Code: Select all

#include "gmp_int.bi"

' Powers of two
print "Some powers of two"
for i as integer = 0 to 128
print "2 ^ " & i & " = " & gmp_int(2) ^ gmp_int(i)
next i

' Big numbers in FOR
print "Big numbers in FOR loop"
for i as gmp_int = gmp_int("10000000000000000") to gmp_int("50000000000000000") step gmp_int("20000000000000000")
print i
next i

' Printing a big number using a non 10 number base.

dim n as gmp_int = gmp_int("123456789123456789123456789123456789")
print "Printing a big number in base 16"
print n, n.getString( 16 )
Posts: 2184
Joined: May 24, 2007 22:10
Location: The Netherlands

Re: Always for me a Big question

I am not aware of any language, having such *native*

Python (2.7) seems to do this fine:

Code: Select all

a = 123456789123456789123456789123456789123456789123456789
b = 987654321987654321987654321987654321987654321987654321
c = a + b + 1

print c

Result: 1111111111111111111111111111111111111111111111111111111

This however, may not be so great:

Code: Select all

a = 123456789123456789123456789123456789123456789123456789.1
b = 987654321987654321987654321987654321987654321987654321
c = a + b + 1

print c

Result: 1.11111111111e+54
Makoto WATANABE
Posts: 196
Joined: Apr 10, 2010 11:41
Location: Japan
Contact:

Re: Always for me a Big question

Dear srvaldez

I am interested in the "Big Number Wrapper" (using GMP int) by Yetifoot http://www.freebasic.net/forum/viewtopic.php?t=7173 .

Unfortunately the "example code" shows a following error:
BigNumberWrapper.bas(19) error 197: Missing overloaded operator: next (with step), before 'i' in 'Next i'

Please teach me if there is a countermeasure method.
srvaldez
Posts: 2578
Joined: Sep 25, 2005 21:54

Re: Always for me a Big question

hello Makoto WATANABE
I made some changes, hope it helps.

gmp_int.bi

Code: Select all

#ifndef __GMP_INT_BI__
#define __GMP_INT_BI__

#include "gmp.bi"

type gmp_int
declare constructor ( )
declare constructor ( byval i as integer )
declare constructor ( byref s as string )
declare constructor ( byref g as gmp_int )
declare destructor ( )
declare operator let ( byref g as gmp_int )
declare operator let ( byval i as Integer )
declare operator let ( byref s as string )
declare operator cast ( ) as Integer
declare operator cast ( ) as string
' For Next Implicit step = +1
Declare Operator For ( )
Declare Operator Step( )
declare operator for ( byref stp as gmp_int )
declare operator step ( byref stp as gmp_int )
declare operator next ( byref end_cond as gmp_int ) as integer
Declare Operator Next( Byref end_cond As gmp_int, Byref step_var As gmp_int ) As Integer
declare function getString ( byval _base as integer = 10 ) as string
num as mpz_ptr = 0
end type

declare operator + ( byref lhs as gmp_int, byref rhs as gmp_int ) as gmp_int
declare operator - ( byref lhs as gmp_int, byref rhs as gmp_int ) as gmp_int
declare operator * ( byref lhs as gmp_int, byref rhs as gmp_int ) as gmp_int
declare operator \ ( byref lhs as gmp_int, byref rhs as gmp_int ) as gmp_int
declare operator / ( byref lhs as gmp_int, byref rhs as gmp_int ) as gmp_int
declare operator ^ ( byref lhs as gmp_int, byval rhs as gmp_int ) as gmp_int
declare operator mod ( byref lhs as gmp_int, byref rhs as gmp_int ) as gmp_int
declare operator and ( byref lhs as gmp_int, byref rhs as gmp_int ) as gmp_int
declare operator or ( byref lhs as gmp_int, byref rhs as gmp_int ) as gmp_int
declare operator xor ( byref lhs as gmp_int, byref rhs as gmp_int ) as gmp_int
declare operator - ( byref rhs as gmp_int ) as gmp_int
declare operator not ( byref rhs as gmp_int ) as gmp_int
declare operator = ( byref lhs as gmp_int, byref rhs as gmp_int ) as integer
declare operator < ( byref lhs as gmp_int, byref rhs as gmp_int ) as integer
declare operator > ( byref lhs as gmp_int, byref rhs as gmp_int ) as integer
declare operator <= ( byref lhs as gmp_int, byref rhs as gmp_int ) as integer
declare operator >= ( byref lhs as gmp_int, byref rhs as gmp_int ) as integer
declare operator <> ( byref lhs as gmp_int, byref rhs as gmp_int ) as integer

#endif '__GMP_INT_BI__

''''#include "gmp_int.bi" 'code above

' Any time we allocate with sizeof( __mpz_struct ), we add the safety net onto the size,
' without this it crashes for me, perhaps the __mpz_struct is declared wrong in gmp.bi,
' whatever the reason it doesn't matter too much, as the struct is only manipulated by
' the gmp functions.
const SAFETY_NET = 20

'::::::::
constructor gmp_int ( )

num = callocate( sizeof( __mpz_struct ) + SAFETY_NET )
mpz_init_set_si( num, 0 )

end constructor

'::::::::
constructor gmp_int ( byval i as integer )

num = callocate( sizeof( __mpz_struct ) + SAFETY_NET )
mpz_init_set_si( num, i )

end constructor

'::::::::
constructor gmp_int ( byref s as string )

num = callocate( sizeof( __mpz_struct ) + SAFETY_NET )
mpz_init_set_str( num, strptr( s ), 10 )

end constructor

'::::::::
constructor gmp_int ( byref g as gmp_int )

num = callocate( sizeof( __mpz_struct ) + SAFETY_NET )
mpz_init_set( num, g.num )

end constructor

'::::::::
destructor gmp_int ( )

mpz_clear( num )
deallocate( num )

end destructor

'::::::::
operator gmp_int.let ( byref g as gmp_int )

mpz_set( num, g.num )

end operator

'::::::::
operator gmp_int.let ( byval i as Integer )

mpz_set_si( num, i )

end operator

'::::::::
operator gmp_int.let ( byref s as string )

mpz_set_str( num, strptr(s), 10 )

end operator

Operator gmp_int.cast ( ) As Integer
Operator = mpz_get_si(num)
End Operator

'::::::::
operator gmp_int.cast ( ) as string

operator = getString( 10 )

end operator

'=====================================================================
' Implicit step   gmp_int.For   gmp_int.Next   gmp_int.Step  is +1

Operator gmp_int.for ( )
End Operator

Operator gmp_int.step ( )
this += 1 'this = this+1 '
End Operator

Operator gmp_int.next ( Byref end_cond As gmp_int ) As Integer
Return this <= end_cond
End Operator

'' explicit step versions
''
Operator gmp_int.for ( Byref step_var As gmp_int )
End Operator

Operator gmp_int.step ( Byref step_var As gmp_int )
this += step_var 'this = this + step_var '
End Operator

Operator gmp_int.next ( Byref end_cond As gmp_int, Byref step_var As gmp_int ) As Integer
If step_var < 0 Then
Return this >= end_cond
Else
Return this <= end_cond
End If
End Operator

'::::::::
function gmp_int.getString ( byval _base as integer = 10 ) as string

dim as zstring ptr s = mpz_get_str( 0, _base, num )

if s then
function = *s
deallocate( s )
end if

end function

'::::::::
operator + ( byref lhs as gmp_int, byref rhs as gmp_int ) as gmp_int

dim as gmp_int result

operator = result

end operator

'::::::::
operator - ( byref lhs as gmp_int, byref rhs as gmp_int ) as gmp_int

dim as gmp_int result

mpz_sub( result.num, lhs.num, rhs.num )

operator = result

end operator

'::::::::
operator * ( byref lhs as gmp_int, byref rhs as gmp_int ) as gmp_int

dim as gmp_int result

mpz_mul( result.num, lhs.num, rhs.num )

operator = result

end operator

'::::::::
operator \ ( byref lhs as gmp_int, byref rhs as gmp_int ) as gmp_int

dim as gmp_int result

mpz_tdiv_q( result.num, lhs.num, rhs.num )

operator = result

end operator

'::::::::
operator / ( byref lhs as gmp_int, byref rhs as gmp_int ) as gmp_int

' This really is quite nasty, but it's the best way I could come up with
' to do an FP divide, while rounding results the way people may expect them.
' 0.5 becomes 1, 0.4 becomes 0, -0.5 becomes -1, -0.4 becomes 0
' I'm not 100% that temp is needed, but I used it just to be safe, for some
' GMP functions it seems a bad idea to pass an mpz as dest and one of the sources.

dim as mpf_ptr l, r, q, half, temp
dim as integer cmp_val
dim as gmp_int result

l = callocate( sizeof( __mpz_struct ) + SAFETY_NET )
r = callocate( sizeof( __mpz_struct ) + SAFETY_NET )
q = callocate( sizeof( __mpz_struct ) + SAFETY_NET )
half = callocate( sizeof( __mpz_struct ) + SAFETY_NET )
temp = callocate( sizeof( __mpz_struct ) + SAFETY_NET )

mpf_init( l )
mpf_init( r )
mpf_init( q )
mpf_init_set_str( half, "0.50", 10 )
mpf_init( temp )

mpf_set_z( l, lhs.num )
mpf_set_z( r, rhs.num )
mpf_div( q, l, r )

cmp_val = mpf_cmp_d( q, 0 )

if cmp_val > 0 then
elseif cmp_val < 0 then
mpf_sub( temp, q, half )
else
mpf_set( temp, q )
end if

mpf_trunc( q, temp )

mpz_set_f( result.num, q )

mpf_clear( l )
mpf_clear( r )
mpf_clear( q )
mpf_clear( half )
mpf_clear( temp )

deallocate( l )
deallocate( r )
deallocate( q )
deallocate( half )
deallocate( temp )

operator = result

end operator

'::::::::
operator ^ ( byref lhs as gmp_int, byval rhs as gmp_int ) as gmp_int

dim as gmp_int result

mpz_pow_ui( result.num, lhs.num, mpz_get_ui( rhs.num ) )

operator = result

end operator

'::::::::
operator mod ( byref lhs as gmp_int, byref rhs as gmp_int ) as gmp_int

dim as gmp_int result

mpz_mod( result.num, lhs.num, rhs.num )

operator = result

end operator

'::::::::
operator and ( byref lhs as gmp_int, byref rhs as gmp_int ) as gmp_int

dim as gmp_int result

mpz_and( result.num, lhs.num, rhs.num )

operator = result

end operator

'::::::::
operator or ( byref lhs as gmp_int, byref rhs as gmp_int ) as gmp_int

dim as gmp_int result

mpz_ior( result.num, lhs.num, rhs.num )

operator = result

end operator

'::::::::
operator xor ( byref lhs as gmp_int, byref rhs as gmp_int ) as gmp_int

dim as gmp_int result

mpz_xor( result.num, lhs.num, rhs.num )

operator = result

end operator

'::::::::
operator - ( byref rhs as gmp_int ) as gmp_int

dim as gmp_int result

mpz_neg( result.num, rhs.num )

operator = result

end operator

'::::::::
operator not ( byref rhs as gmp_int ) as gmp_int

dim as gmp_int result

mpz_com( result.num, rhs.num )

operator = result

end operator

'::::::::
operator = ( byref lhs as gmp_int, byref rhs as gmp_int ) as integer

operator = (mpz_cmp( lhs.num, rhs.num ) = 0)

end operator

'::::::::
operator < ( byref lhs as gmp_int, byref rhs as gmp_int ) as integer

operator = (mpz_cmp( lhs.num, rhs.num ) < 0)

end operator

'::::::::
operator > ( byref lhs as gmp_int, byref rhs as gmp_int ) as integer

operator = (mpz_cmp( lhs.num, rhs.num ) > 0)

end operator

'::::::::
operator <= ( byref lhs as gmp_int, byref rhs as gmp_int ) as integer

operator = (mpz_cmp( lhs.num, rhs.num ) <= 0)

end operator

'::::::::
operator >= ( byref lhs as gmp_int, byref rhs as gmp_int ) as integer

operator = (mpz_cmp( lhs.num, rhs.num ) >= 0)

end operator

'::::::::
operator <> ( byref lhs as gmp_int, byref rhs as gmp_int ) as integer

operator = (mpz_cmp( lhs.num, rhs.num ) <> 0)

end operator

test.bas

Code: Select all

#include "gmp_int.bi"

dim as gmp_int i, two = 2 'if the number is small
' if the number is larger than FB integer then use: two = gmp_int("2")
dim as integer k

' Powers of two
print "Some powers of two"
for i = 0 to 128
print "2 ^ " & i & " = " & two ^ i
next i

print
print "casting a gmp_int to a FreeBASIC Integer"
print "this should only be done if you know the gmp_int will fit in a Integer"

k = two
print "k = two ->";k
frisian
Posts: 249
Joined: Oct 08, 2009 17:25

Re: Always for me a Big question

Gmp_int.bi has two problems in the floating point division (/) routine. First the gmp floats need a 16 byte structure (__mpf_struct) but they get a 12 byte structure (__mpz_struct) which result in data stored outside the structure and most likely overwriting data in the next structure, hence crashes.
Solution: change __mpz_struct to __mpf_struct.

The size for gmp_floats is fixed where as the size for integers depends on the size of the number. The default size for floats is 32bit.
Solution: find the size in bits of lhs and rhs. Take the biggest of the two. Use mpf_init2 instead of mpf_init to give the floats a size that is at least equal to the size of the integers

Tweaked the Constructor ( ByRef s As String) to Constructor ( ByRef s As String, ByVal _base As Long = 10 ) to make it possible to enter numbers in base 2 to 62. Default = 10 (decimal)

i = gmp_int("1234") = gmp_int("1234", 10)
i = gmp_int("abcd", 16) ' hexadecimal
i = gmp_int("1001", 2) ' binary
i = gmp_int("7777", 8) ' octal

gmp_int.bi

Code: Select all

#Ifndef __GMP_INT_BI__
#Define __GMP_INT_BI__

#Include Once "gmp.bi"

Type gmp_int
Declare Constructor ( )
Declare Constructor ( ByVal i As Integer )
Declare Constructor ( ByRef s As String, ByVal _base As Long = 10 )
Declare Constructor ( ByRef g As gmp_int )
Declare Destructor ( )
Declare Operator Let ( ByRef g As gmp_int )
Declare Operator Let ( ByVal i As Integer )
Declare Operator Let ( ByRef s As String )
Declare Operator Cast ( ) As Integer
Declare Operator Cast ( ) As String
' For Next Implicit step = +1
Declare Operator For ( )
Declare Operator Step( )
Declare Operator For ( ByRef stp As gmp_int )
Declare Operator Step ( ByRef stp As gmp_int )
Declare Operator Next ( ByRef end_cond As gmp_int ) As Integer
Declare Operator Next( ByRef end_cond As gmp_int, ByRef step_var As gmp_int ) As Integer
Declare Function getString ( ByVal _base As Integer = 10 ) As String
num As mpz_ptr = 0
End Type

Declare Operator + ( ByRef lhs As gmp_int, ByRef rhs As gmp_int ) As gmp_int
Declare Operator - ( ByRef lhs As gmp_int, ByRef rhs As gmp_int ) As gmp_int
Declare Operator * ( ByRef lhs As gmp_int, ByRef rhs As gmp_int ) As gmp_int
Declare Operator \ ( ByRef lhs As gmp_int, ByRef rhs As gmp_int ) As gmp_int
Declare Operator / ( ByRef lhs As gmp_int, ByRef rhs As gmp_int ) As gmp_int
Declare Operator ^ ( ByRef lhs As gmp_int, ByVal rhs As gmp_int ) As gmp_int
Declare Operator Mod ( ByRef lhs As gmp_int, ByRef rhs As gmp_int ) As gmp_int
Declare Operator And ( ByRef lhs As gmp_int, ByRef rhs As gmp_int ) As gmp_int
Declare Operator Or ( ByRef lhs As gmp_int, ByRef rhs As gmp_int ) As gmp_int
Declare Operator Xor ( ByRef lhs As gmp_int, ByRef rhs As gmp_int ) As gmp_int
Declare Operator - ( ByRef rhs As gmp_int ) As gmp_int
Declare Operator Not ( ByRef rhs As gmp_int ) As gmp_int
Declare Operator = ( ByRef lhs As gmp_int, ByRef rhs As gmp_int ) As Integer
Declare Operator < ( ByRef lhs As gmp_int, ByRef rhs As gmp_int ) As Integer
Declare Operator > ( ByRef lhs As gmp_int, ByRef rhs As gmp_int ) As Integer
Declare Operator <= ( ByRef lhs As gmp_int, ByRef rhs As gmp_int ) As Integer
Declare Operator >= ( ByRef lhs As gmp_int, ByRef rhs As gmp_int ) As Integer
Declare Operator <> ( ByRef lhs As gmp_int, ByRef rhs As gmp_int ) As Integer

#EndIf '__GMP_INT_BI__

''''#include "gmp_int.bi" 'code above

' Any time we allocate with sizeof( __mpz_struct ), we add the safety net onto the size,
' without this it crashes for me, perhaps the __mpz_struct is declared wrong in gmp.bi,
' whatever the reason it doesn't matter too much, as the struct is only manipulated by
' the gmp functions.
' Const SAFETY_NET = 20
Const SAFETY_NET = 0 ' not needed

'::::::::
Constructor gmp_int ( )

num = Callocate( SizeOf( __mpz_struct ) + SAFETY_NET )
' mpz_init_set_si( num, 0 )
mpz_init( num )
End Constructor

'::::::::
Constructor gmp_int ( ByVal i As Integer )

num = Callocate( SizeOf( __mpz_struct ) + SAFETY_NET )
mpz_init_set_si( num, i )

End Constructor

'::::::::
Constructor gmp_int ( ByRef s As String, ByVal _base As Long = 10 )

num = Callocate( SizeOf( __mpz_struct ) + SAFETY_NET )
mpz_init_set_str( num, StrPtr( s ), _base )

End Constructor

'::::::::
Constructor gmp_int ( ByRef g As gmp_int )

num = Callocate( SizeOf( __mpz_struct ) + SAFETY_NET )
mpz_init_set( num, g.num )

End Constructor

'::::::::
Destructor gmp_int ( )

mpz_clear( num )
DeAllocate( num )

End Destructor

'::::::::
Operator gmp_int.let ( ByRef g As gmp_int )

mpz_set( num, g.num )

End Operator

'::::::::
Operator gmp_int.let ( ByVal i As Integer )

mpz_set_si( num, i )

End Operator

'::::::::
Operator gmp_int.let ( ByRef s As String )

mpz_set_str( num, StrPtr(s), 10 )

End Operator

Operator gmp_int.cast ( ) As Integer
Operator = mpz_get_si(num)
End Operator

'::::::::
Operator gmp_int.cast ( ) As String

Operator = getString( 10 )

End Operator

'=====================================================================
' Implicit step   gmp_int.For   gmp_int.Next   gmp_int.Step  is +1

Operator gmp_int.for ( )
End Operator

Operator gmp_int.step ( )
This += 1 'this = this+1 '
End Operator

Operator gmp_int.next ( ByRef end_cond As gmp_int ) As Integer
Return This <= end_cond
End Operator

'' explicit step versions
''
Operator gmp_int.for ( ByRef step_var As gmp_int )
End Operator

Operator gmp_int.step ( ByRef step_var As gmp_int )
This += step_var 'this = this + step_var '
End Operator

Operator gmp_int.next ( ByRef end_cond As gmp_int, ByRef step_var As gmp_int ) As Integer
If step_var < 0 Then
Return This >= end_cond
Else
Return This <= end_cond
End If
End Operator

'::::::::
Function gmp_int.getString ( ByVal _base As Integer = 10 ) As String

Dim As ZString Ptr s = mpz_get_str( 0, _base, num )

If s Then
Function = *s
DeAllocate( s )
End If

End Function

'::::::::
Operator + ( ByRef lhs As gmp_int, ByRef rhs As gmp_int ) As gmp_int

Dim As gmp_int result

Operator = result

End Operator

'::::::::
Operator - ( ByRef lhs As gmp_int, ByRef rhs As gmp_int ) As gmp_int

Dim As gmp_int result

mpz_sub( result.num, lhs.num, rhs.num )

Operator = result

End Operator

'::::::::
Operator * ( ByRef lhs As gmp_int, ByRef rhs As gmp_int ) As gmp_int

Dim As gmp_int result

mpz_mul( result.num, lhs.num, rhs.num )

Operator = result

End Operator

'::::::::
Operator \ ( ByRef lhs As gmp_int, ByRef rhs As gmp_int ) As gmp_int

Dim As gmp_int result

mpz_tdiv_q( result.num, lhs.num, rhs.num )

Operator = result

End Operator

'::::::::
Operator / ( ByRef lhs As gmp_int, ByRef rhs As gmp_int ) As gmp_int

' This really is quite nasty, but it's the best way I could come up with
' to do an FP divide, while rounding results the way people may expect them.
' 0.5 becomes 1, 0.4 becomes 0, -0.5 becomes -1, -0.4 becomes 0
' I'm not 100% that temp is needed, but I used it just to be safe, for some
' GMP functions it seems a bad idea to pass an mpz as dest and one of the sources.

Dim As mpf_ptr l, r, q, half, temp
Dim As gmp_int result

' size for gmp floats is fixed, this could lead to loss of precision
' the size is set by mpf_set_default_prec or by using mpf_init2( 'var', size)
' find the size of lhs and rhs, take the longest size and add 32 bit (9 digits)
Dim As ULong l1 = mpz_sizeinbase ( lhs.num , 2)
Dim As ULong r1 = mpz_sizeinbase ( rhs.num , 2)
If r1 > l1 Then l1 = r1
l1 = l1 +32

' l = callocate( sizeof( __mpz_struct ) + SAFETY_NET )
' r = callocate( sizeof( __mpz_struct ) + SAFETY_NET )
' q = callocate( sizeof( __mpz_struct ) + SAFETY_NET )
' half = callocate( sizeof( __mpz_struct ) + SAFETY_NET )
' temp = callocate( sizeof( __mpz_struct ) + SAFETY_NET )

' sizeof( __mpz_struct ) = 12, sizeof( __mpf_struct ) = 16
l = Callocate( SizeOf( __mpf_struct ) )
r = Callocate( SizeOf( __mpf_struct ) )
q = Callocate( SizeOf( __mpf_struct ) )
half = Callocate( SizeOf( __mpf_struct ) )
temp = Callocate( SizeOf( __mpf_struct ) )

mpf_init2( l, l1 )          ' set the size for l to l1
mpf_init2( r, l1 )          ' set the size for l to l1
mpf_init2( q, l1 )          ' set the size for l to l1
mpf_init_set_d( half, .5 )
mpf_init2( temp, l1 )       ' set the size for l to l1

mpf_set_z( l, lhs.num )
mpf_set_z( r, rhs.num )
mpf_div( q, l, r )

Dim As Long cmp_val = mpf_cmp_d( q, 0 )

If cmp_val > 0 Then
ElseIf cmp_val < 0 Then
mpf_sub( temp, q, half )
Else
mpf_set( temp, q )
End If

' mpf_trunc( q, temp )
' mpz_set_f( result.num, q )
' mpz_set_d, mpz_set_q and mpz_set_f truncate 'op' to make it an integer.

mpz_set_f( result.num, temp)

mpf_clear( l )
mpf_clear( r )
mpf_clear( q )
mpf_clear( half )
mpf_clear( temp )

DeAllocate( l )
DeAllocate( r )
DeAllocate( q )
DeAllocate( half )
DeAllocate( temp )

Operator = result

End Operator

'::::::::
Operator ^ ( ByRef lhs As gmp_int, ByVal rhs As gmp_int ) As gmp_int

Dim As gmp_int result

mpz_pow_ui( result.num, lhs.num, mpz_get_ui( rhs.num ) )

Operator = result

End Operator

'::::::::
Operator Mod ( ByRef lhs As gmp_int, ByRef rhs As gmp_int ) As gmp_int

Dim As gmp_int result

mpz_mod( result.num, lhs.num, rhs.num )

Operator = result

End Operator

'::::::::
Operator And ( ByRef lhs As gmp_int, ByRef rhs As gmp_int ) As gmp_int

Dim As gmp_int result

mpz_and( result.num, lhs.num, rhs.num )

Operator = result

End Operator

'::::::::
Operator Or ( ByRef lhs As gmp_int, ByRef rhs As gmp_int ) As gmp_int

Dim As gmp_int result

mpz_ior( result.num, lhs.num, rhs.num )

Operator = result

End Operator

'::::::::
Operator Xor ( ByRef lhs As gmp_int, ByRef rhs As gmp_int ) As gmp_int

Dim As gmp_int result

mpz_xor( result.num, lhs.num, rhs.num )

Operator = result

End Operator

'::::::::
Operator - ( ByRef rhs As gmp_int ) As gmp_int

Dim As gmp_int result

mpz_neg( result.num, rhs.num )

Operator = result

End Operator

'::::::::
Operator Not ( ByRef rhs As gmp_int ) As gmp_int

Dim As gmp_int result

mpz_com( result.num, rhs.num )

Operator = result

End Operator

'::::::::
Operator = ( ByRef lhs As gmp_int, ByRef rhs As gmp_int ) As Integer

Operator = (mpz_cmp( lhs.num, rhs.num ) = 0)

End Operator

'::::::::
Operator < ( ByRef lhs As gmp_int, ByRef rhs As gmp_int ) As Integer

Operator = (mpz_cmp( lhs.num, rhs.num ) < 0)

End Operator

'::::::::
Operator > ( ByRef lhs As gmp_int, ByRef rhs As gmp_int ) As Integer

Operator = (mpz_cmp( lhs.num, rhs.num ) > 0)

End Operator

'::::::::
Operator <= ( ByRef lhs As gmp_int, ByRef rhs As gmp_int ) As Integer

Operator = (mpz_cmp( lhs.num, rhs.num ) <= 0)

End Operator

'::::::::
Operator >= ( ByRef lhs As gmp_int, ByRef rhs As gmp_int ) As Integer

Operator = (mpz_cmp( lhs.num, rhs.num ) >= 0)

End Operator

'::::::::
Operator <> ( ByRef lhs As gmp_int, ByRef rhs As gmp_int ) As Integer

Operator = (mpz_cmp( lhs.num, rhs.num ) <> 0)

End Operator

littletest.bas

Code: Select all

#Include Once "gmp_int.bi"

Dim As gmp_int i
Print
Print gmp_int ("1"+String(40, "0")) / gmp_int(3)
Print

i = gmp_int(String(32,"F"), 16)
Print i

i = gmp_int(String(32,"f"), 16)
Print i

i = gmp_int(string(128,"1"), 2)
Print i

Sleep
Last edited by frisian on May 06, 2017 8:56, edited 1 time in total.
srvaldez
Posts: 2578
Joined: Sep 25, 2005 21:54

Re: Always for me a Big question

thanks frisian
this was Yetifoot's code and I did not check for correctness other than fixing the for loop code, thanks for the fix. :-)
 in the test code, next to last line you missed a right parenthesis
i = gmp_int(string(128,"1", 2) should be i = gmp_int(string(128,"1"), 2) also you missed a print i
frisian
Posts: 249
Joined: Oct 08, 2009 17:25

Re: Always for me a Big question

srvaldez wrote: in the test code, next to last line you missed a right parenthesis
i = gmp_int(string(128,"1", 2) should be i = gmp_int(string(128,"1"), 2) also you missed a print i

fixed the code in my previous post, thanks.

I have cleaned the listing of gmp_int.bi and added shl and shr also added a function to convert a big int into base 2 to 62 string.

gmp_int.bi

Code: Select all

' Original by yetifoot http://www.freebasic.net/forum/viewtopic.php?t=7173
' May 2017: srvaldez
' fixed the loop code
' May 2017: frisian
' corrected and improved the floating point division (/), this makes SAFETY_NET obsolete
' added operators Shr and Shl
' added function gmp_int_2_base that returns a string of a gmp_int number in base 2 to 62 (default 10, decimal)

#Ifndef __GMP_INT_BI__
#Define __GMP_INT_BI__

#Include Once "gmp.bi"

Type gmp_int
Declare Constructor ( )
Declare Constructor ( ByVal i As Integer )
Declare Constructor ( ByRef s As String, ByVal _base As Integer = 10 )
Declare Constructor ( ByRef g As gmp_int )
Declare Destructor ( )
Declare Operator Let ( ByRef g As gmp_int )
Declare Operator Let ( ByVal i As Integer )
Declare Operator Let ( ByRef s As String )
Declare Operator Cast ( ) As Integer
Declare Operator Cast ( ) As String
' For Next Implicit step = +1
Declare Operator For ( )
Declare Operator Step( )
Declare Operator For ( ByRef stp As gmp_int )
Declare Operator Step ( ByRef stp As gmp_int )
Declare Operator Next ( ByRef end_cond As gmp_int ) As Integer
Declare Operator Next( ByRef end_cond As gmp_int, ByRef step_var As gmp_int ) As Integer
Declare Function getString ( ByVal _base As Integer = 10 ) As String
num As mpz_ptr = 0
End Type

Declare Operator + ( ByRef lhs As gmp_int, ByRef rhs As gmp_int ) As gmp_int
Declare Operator - ( ByRef lhs As gmp_int, ByRef rhs As gmp_int ) As gmp_int
Declare Operator * ( ByRef lhs As gmp_int, ByRef rhs As gmp_int ) As gmp_int
Declare Operator \ ( ByRef lhs As gmp_int, ByRef rhs As gmp_int ) As gmp_int
Declare Operator / ( ByRef lhs As gmp_int, ByRef rhs As gmp_int ) As gmp_int
Declare Operator ^ ( ByRef lhs As gmp_int, ByVal rhs As gmp_int ) As gmp_int
Declare Operator Mod ( ByRef lhs As gmp_int, ByRef rhs As gmp_int ) As gmp_int
Declare Operator And ( ByRef lhs As gmp_int, ByRef rhs As gmp_int ) As gmp_int
Declare Operator Or ( ByRef lhs As gmp_int, ByRef rhs As gmp_int ) As gmp_int
Declare Operator Xor ( ByRef lhs As gmp_int, ByRef rhs As gmp_int ) As gmp_int
Declare Operator Shl ( ByRef lhs As gmp_int, ByVal rhs As Integer ) As gmp_int
Declare Operator Shr ( ByRef lhs As gmp_int, ByVal rhs As Integer ) As gmp_int
Declare Operator - ( ByRef rhs As gmp_int ) As gmp_int
Declare Operator Not ( ByRef rhs As gmp_int ) As gmp_int
Declare Operator = ( ByRef lhs As gmp_int, ByRef rhs As gmp_int ) As Integer
Declare Operator < ( ByRef lhs As gmp_int, ByRef rhs As gmp_int ) As Integer
Declare Operator > ( ByRef lhs As gmp_int, ByRef rhs As gmp_int ) As Integer
Declare Operator <= ( ByRef lhs As gmp_int, ByRef rhs As gmp_int ) As Integer
Declare Operator >= ( ByRef lhs As gmp_int, ByRef rhs As gmp_int ) As Integer
Declare Operator <> ( ByRef lhs As gmp_int, ByRef rhs As gmp_int ) As Integer

#EndIf '__GMP_INT_BI__

''''#include "gmp_int.bi" 'code above

'::::::::
Constructor gmp_int ( )

num = Callocate( SizeOf( __mpz_struct ) )
mpz_init( num )

End Constructor

'::::::::
Constructor gmp_int ( ByVal i As Integer )

num = Callocate( SizeOf( __mpz_struct ) )
mpz_init_set_si( num, i )

End Constructor

'::::::::
Constructor gmp_int ( ByRef s As String, ByVal _base As Integer = 10 )

num = Callocate( SizeOf( __mpz_struct ) )
mpz_init_set_str( num, StrPtr( s ), _base )

End Constructor

'::::::::
Constructor gmp_int ( ByRef g As gmp_int )

num = Callocate( SizeOf( __mpz_struct ) )
mpz_init_set( num, g.num )

End Constructor

'::::::::
Destructor gmp_int ( )

mpz_clear( num )
DeAllocate( num )

End Destructor

'::::::::
Operator gmp_int.let ( ByRef g As gmp_int )

mpz_set( num, g.num )

End Operator

'::::::::
Operator gmp_int.let ( ByVal i As Integer )

mpz_set_si( num, i )

End Operator

'::::::::
Operator gmp_int.let ( ByRef s As String )

mpz_set_str( num, StrPtr(s), 10 )

End Operator

Operator gmp_int.cast ( ) As Integer
Operator = mpz_get_si(num)
End Operator

'::::::::
Operator gmp_int.cast ( ) As String

Operator = getString( 10 )

End Operator

'=====================================================================
' Implicit step   gmp_int.For   gmp_int.Next   gmp_int.Step  is +1

Operator gmp_int.for ( )
End Operator

Operator gmp_int.step ( )
This += 1 'this = this+1 '
End Operator

Operator gmp_int.next ( ByRef end_cond As gmp_int ) As Integer
Return This <= end_cond
End Operator

'' explicit step versions
''
Operator gmp_int.for ( ByRef step_var As gmp_int )
End Operator

Operator gmp_int.step ( ByRef step_var As gmp_int )
This += step_var 'this = this + step_var '
End Operator

Operator gmp_int.next ( ByRef end_cond As gmp_int, ByRef step_var As gmp_int ) As Integer
If step_var < 0 Then
Return This >= end_cond
Else
Return This <= end_cond
End If
End Operator

'::::::::
Function gmp_int.getString ( ByVal _base As Integer = 10 ) As String

Dim As ZString Ptr s = mpz_get_str( 0, _base, num )

If s Then
Function = *s
DeAllocate( s )
End If

End Function

'::::::::
Operator + ( ByRef lhs As gmp_int, ByRef rhs As gmp_int ) As gmp_int

Dim As gmp_int result

Operator = result

End Operator

'::::::::
Operator - ( ByRef lhs As gmp_int, ByRef rhs As gmp_int ) As gmp_int

Dim As gmp_int result

mpz_sub( result.num, lhs.num, rhs.num )

Operator = result

End Operator

'::::::::
Operator * ( ByRef lhs As gmp_int, ByRef rhs As gmp_int ) As gmp_int

Dim As gmp_int result

mpz_mul( result.num, lhs.num, rhs.num )

Operator = result

End Operator

'::::::::
Operator \ ( ByRef lhs As gmp_int, ByRef rhs As gmp_int ) As gmp_int

Dim As gmp_int result

mpz_tdiv_q( result.num, lhs.num, rhs.num )

Operator = result

End Operator

'::::::::
Operator / ( ByRef lhs As gmp_int, ByRef rhs As gmp_int ) As gmp_int

' This really is quite nasty, but it's the best way I could come up with
' to do an FP divide, while rounding results the way people may expect them.
' 0.5 becomes 1, 0.4 becomes 0, -0.5 becomes -1, -0.4 becomes 0
' I'm not 100% that temp is needed, but I used it just to be safe, for some
' GMP functions it seems a bad idea to pass an mpz as dest and one of the sources.

Dim As mpf_ptr l, r, q, half, temp
Dim As gmp_int result

' size for gmp floats is fixed, this could lead to loss of precision
' the size is set by mpf_set_default_prec or by using mpf_init2( 'var', size)
' find the size of lhs and rhs, take the longest size and add 32 bit (9 digits)
Dim As UInteger l1 = mpz_sizeinbase ( lhs.num, 2 )
Dim As UInteger r1 = mpz_sizeinbase ( rhs.num, 2 )
If r1 > l1 Then l1 = r1
l1 = l1 +32

l = Callocate( SizeOf( __mpf_struct ) )
r = Callocate( SizeOf( __mpf_struct ) )
q = Callocate( SizeOf( __mpf_struct ) )
half = Callocate( SizeOf( __mpf_struct ) )
temp = Callocate( SizeOf( __mpf_struct ) )

mpf_init2( l, l1 )          ' set the size for l to l1
mpf_init2( r, l1 )          ' set the size for r to l1
mpf_init2( q, l1 )          ' set the size for q to l1
mpf_init_set_d( half, .5 )
mpf_init2( temp, l1 )       ' set the size for temp to l1

mpf_set_z( l, lhs.num )
mpf_set_z( r, rhs.num )
mpf_div( q, l, r )

Dim As Integer cmp_val = mpf_cmp_d( q, 0 )

If cmp_val > 0 Then
ElseIf cmp_val < 0 Then
mpf_sub( temp, q, half )
Else
mpf_set( temp, q )
End If

mpz_set_f( result.num, temp)

mpf_clear( l )
mpf_clear( r )
mpf_clear( q )
mpf_clear( half )
mpf_clear( temp )

DeAllocate( l )
DeAllocate( r )
DeAllocate( q )
DeAllocate( half )
DeAllocate( temp )

Operator = result

End Operator

'::::::::
Operator ^ ( ByRef lhs As gmp_int, ByVal rhs As gmp_int ) As gmp_int

Dim As gmp_int result

mpz_pow_ui( result.num, lhs.num, mpz_get_ui( rhs.num ) )

Operator = result

End Operator

'::::::::
Operator Mod ( ByRef lhs As gmp_int, ByRef rhs As gmp_int ) As gmp_int

Dim As gmp_int result

mpz_mod( result.num, lhs.num, rhs.num )

Operator = result

End Operator

'::::::::
Operator And ( ByRef lhs As gmp_int, ByRef rhs As gmp_int ) As gmp_int

Dim As gmp_int result

mpz_and( result.num, lhs.num, rhs.num )

Operator = result

End Operator

'::::::::
Operator Or ( ByRef lhs As gmp_int, ByRef rhs As gmp_int ) As gmp_int

Dim As gmp_int result

mpz_ior( result.num, lhs.num, rhs.num )

Operator = result

End Operator

'::::::::
Operator Xor ( ByRef lhs As gmp_int, ByRef rhs As gmp_int ) As gmp_int

Dim As gmp_int result

mpz_xor( result.num, lhs.num, rhs.num )

Operator = result

End Operator

Operator Shl ( ByRef lhs As gmp_int, ByVal rhs As Integer ) As gmp_int

Dim As gmp_int result

mpz_mul_2exp( result.num, lhs.num, rhs )

Operator = result

End Operator

Operator Shr ( ByRef lhs As gmp_int, ByVal rhs As Integer ) As gmp_int

Dim As gmp_int result

mpz_tdiv_q_2exp( result.num, lhs.num, rhs )

Operator = result

End Operator

'::::::::
Operator - ( ByRef rhs As gmp_int ) As gmp_int

Dim As gmp_int result

mpz_neg( result.num, rhs.num )

Operator = result

End Operator

'::::::::
Operator Not ( ByRef rhs As gmp_int ) As gmp_int

Dim As gmp_int result

mpz_com( result.num, rhs.num )

Operator = result

End Operator

'::::::::
Operator = ( ByRef lhs As gmp_int, ByRef rhs As gmp_int ) As Integer

Operator = (mpz_cmp( lhs.num, rhs.num ) = 0)

End Operator

'::::::::
Operator < ( ByRef lhs As gmp_int, ByRef rhs As gmp_int ) As Integer

Operator = (mpz_cmp( lhs.num, rhs.num ) < 0)

End Operator

'::::::::
Operator > ( ByRef lhs As gmp_int, ByRef rhs As gmp_int ) As Integer

Operator = (mpz_cmp( lhs.num, rhs.num ) > 0)

End Operator

'::::::::
Operator <= ( ByRef lhs As gmp_int, ByRef rhs As gmp_int ) As Integer

Operator = (mpz_cmp( lhs.num, rhs.num ) <= 0)

End Operator

'::::::::
Operator >= ( ByRef lhs As gmp_int, ByRef rhs As gmp_int ) As Integer

Operator = (mpz_cmp( lhs.num, rhs.num ) >= 0)

End Operator

'::::::::
Operator <> ( ByRef lhs As gmp_int, ByRef rhs As gmp_int ) As Integer

Operator = (mpz_cmp( lhs.num, rhs.num ) <> 0)

End Operator

' return a string of a gmp_int number in base 2 to 62 (default 10, decimal)
Function gmp_int_2_base (ByRef bigint As gmp_int, ByVal _base As Integer = 10 ) As String

Dim As ZString Ptr s = mpz_get_str( 0, _base, bigint.num )

If s Then
Function = *s
DeAllocate( s )
End If

End Function

test.bas added a few examples of shl and shr

Code: Select all

#Include Once "gmp_int.bi"

Dim as gmp_int i, two = 2 'if the number is small
' if the number is larger than FB integer then use: two = gmp_int("2")
dim as integer k

' Powers of two
print "Some powers of two"
for i = 0 to 128
print "2 ^ " & i & " = " & two ^ i
next i

print
print "casting a gmp_int to a FreeBASIC Integer"
print "this should only be done if you know the gmp_int will fit in a Integer"

k = two
print "k = two ->";k

print
i = "1" + string(35, "0")
i = i + 1
Print i; " / 3 = "; i / 3
Print

i = gmp_int(string(40,"1"), 2)
Print "&B" + String(40,"1") + " = ";i

Print
Print i; " shr 39 = "; i Shr 39
Print

i = 1
Print i; " shl 128 = "; i Shl 128

Print
i = "1234567890"
Print i; " in base 62 = "; gmp_int_2_base(i, 62)
Print i; " in base 16 = "; gmp_int_2_base(i, 16)
Print i; " in base 8  = "; gmp_int_2_base(i, 8)
Print i; " in base 2  = "; gmp_int_2_base(i, 2)

Print
i = gmp_int("09azAZ", 62)
Print "09azAZ(62) = "; i

Sleep
Makoto WATANABE
Posts: 196
Joined: Apr 10, 2010 11:41
Location: Japan
Contact:

Re: Always for me a Big question

Dear srvaldez
Dear frisian

You two have always touched my interest and gave me perfect teachings.
I am very grateful.

Code: Select all

#Include Once "gmp_int.bi"

Dim As gmp_int a = gmp_int("123456789123456789123456789123456789123456789123456789")
Dim As gmp_int b = gmp_int("987654321987654321987654321987654321987654321987654321") ,c
c = a + b + 1

Print c
Sleep

Result: 1111111111111111111111111111111111111111111111111111111
srvaldez
Posts: 2578
Joined: Sep 25, 2005 21:54

Re: Always for me a Big question

thank you frisian for the update, perhaps you should post it in the tips & tricks section?
student1347
Posts: 49
Joined: Dec 16, 2011 3:48

Re: Always for me a Big question

Thanks as many as BIG NUMBERS for all the answers.But why gmp_int.bi does not work with fb version 0.24.0 but it is ok with version 1.05.0.thank you all again.
dodicat
Posts: 6766
Joined: Jan 10, 2006 20:30
Location: Scotland

Re: Always for me a Big question

If you have put libgmp.a into lib/win32 in version 0.24.0 then you should remove or rename libgmp.dll.a from the same folder.
student1347
Posts: 49
Joined: Dec 16, 2011 3:48

Re: Always for me a Big question

Dear dodicat I did it but It again does not work.here is the errors
F:\Program Files\fbedit1076c\FreeBASIC-0.24.0-win32\inc\gmp.bi(136) error 9: Expected expression, found 'function' in 'declare sub __gmp_get_memory_functions(byval as typeof(function(byval as uinteger) as any ptr) ptr, byval as typeof(function(byval as any ptr, byval as uinteger, byval as uinteger) as any ptr) ptr, byval as typeof(sub(byval as any ptr, byval as uinteger)) ptr)'
F:\Program Files\fbedit1076c\FreeBASIC-0.24.0-win32\inc\gmp.bi(137) error 9: Expected expression, found 'function' in 'declare sub mp_get_memory_functions alias "__gmp_get_memory_functions"(byval as typeof(function(byval as uinteger) as any ptr) ptr, byval as typeof(function(byval as any ptr, byval as uinteger, byval as uinteger) as any ptr) ptr, byval as typeof(sub(byval as any ptr, byval as uinteger)) ptr)'