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

Post by student1347 »

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 ?
Thank you in advance.
Last edited by student1347 on May 05, 2017 11:53, edited 1 time in total.
MrSwiss
Posts: 3910
Joined: Jun 02, 2013 9:27
Location: Switzerland

Re: Always for me a Big question

Post by MrSwiss »

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: 7976
Joined: Jan 10, 2006 20:30
Location: Scotland

Re: Always for me a Big question

Post by dodicat »

get the gmp library.
gmp 6.1.2
from srvaldez (top post)
http://www.freebasic.net/forum/viewtopi ... 55#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 __mpz_struct Intanswer
    mpz_init( @Intanswer)
    mpz_fac_ui(@Intanswer,n)
    Dim As ZString Ptr s = mpz_get_str(0, numberbase, @intanswer)
    mpz_clear(@Intanswer)
    function= Trim(*s)
    deallocate(s)
End Function

print factorial(150,16)
print
print factorial(150,10)
sleep
 
srvaldez
Posts: 3373
Joined: Sep 25, 2005 21:54

Re: Always for me a Big question

Post by srvaldez »

hello student1347
you may also be interested in the "Big Number Wrapper" (using GMP int) by Yetifoot http://www.freebasic.net/forum/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 )
badidea
Posts: 2586
Joined: May 24, 2007 22:10
Location: The Netherlands

Re: Always for me a Big question

Post by badidea »

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: 231
Joined: Apr 10, 2010 11:41
Location: Japan
Contact:

Re: Always for me a Big question

Post by Makoto WATANABE »

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: 3373
Joined: Sep 25, 2005 21:54

Re: Always for me a Big question

Post by srvaldez »

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

	mpz_add( 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_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
		mpf_add( temp, q, half )
	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

Post by frisian »

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

    mpz_add( 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_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
        mpf_add( temp, q, half )
    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: 3373
Joined: Sep 25, 2005 21:54

Re: Always for me a Big question

Post by srvaldez »

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. :-)
[edit] 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

Post by frisian »

srvaldez wrote: [edit] 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
' corrected some errors in comments i made, cleaned the listing 
' 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

    mpz_add( 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_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
        mpf_add( temp, q, half )
    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: 231
Joined: Apr 10, 2010 11:41
Location: Japan
Contact:

Re: Always for me a Big question

Post by Makoto WATANABE »

Dear srvaldez
Dear frisian

Thanks for your quick reply.
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: 3373
Joined: Sep 25, 2005 21:54

Re: Always for me a Big question

Post by srvaldez »

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

Post by student1347 »

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: 7976
Joined: Jan 10, 2006 20:30
Location: Scotland

Re: Always for me a Big question

Post by dodicat »

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

Post by student1347 »

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)'
Post Reply