FreeBASIC マニュアルのトップに戻る

FreeBASIC Big number wrapper(GMP int 使用)

目次→フォーラム→FreeBASIC→補足Big number wrapper (using GMP int)←オリジナル・フォーラム

Big number wrapper(GMP int 使用) 左にメニュー・フレームが表示されていない場合は、ここをクリックして下さい

←リンク元に戻る プログラム開発関連に戻る

このページは、yetifoot さんが、フォーラム Tips and TricksBig number wrapper (using GMP int) で提起したラッパー(省略関数)を、
BeginnersAlways for me a Big question および、
Tips and TricksBig Number Wrapper (GMP_INT.BI) で、srvaldez さんと frisian さんが改良した gmp_int.bi と、その使い方のサンプル・プログラムを日本語化して紹介します。

環境準備:
任意精度算術ライブラリ GMP の関連ファイルをダウンロードして該当する該当フォルダに保存します。

注意:コンパイル時に、下記のエラーが表示される場合:
C:\Tool\FreeBASIC\bin\win32\ld.exe: cannot find -lgmp
これは、linker のエラーで、***.dll.a (または ***.a または lib***.a または ***.dll)が見つからないからです。
gmp 6.2.1 and mpfr 4.1.0 ←最新版の関連ファイルをダウンロードできます。
解凍した
gmp-6.2.0\win32\static\libgmp.a
又は、
gmp+mpfr\32-bit\static\libgmp.a

C:\Tool\FreeBASIC\lib\win32\libgmp.a
として保存します。


使用例のプログラム

以下を、例えば BigNumberWrapperTestJP.bas という名前で保存します。
同じフォルダに、gmp_int.bi を保存したうえで、コンパイル実行します。
'https://www.freebasic.net/forum/viewtopic.php?f=7&t=25684
'by frisian ≫ May 18, 2017 20:33
'Last edited by frisian on May 22, 2017 21:09

#Include Once "gmp_int.bi"

Dim As gmp_int i, j, two = 2 '数字が小さい場合
' 数値が FB の integer より大きい場合は、こちらを使います: two = gmp_int("2")
Dim As Integer k

' 2の累乗
Print "2 の累乗を幾つか表示します。"
Print "(以降何度か中断します。何かキー入力でデモを継続します。)"
Sleep
For i = 0 To 128
   Print "2 ^ " & i & " = " & two ^ i
Next i

Print
Sleep

Print "gmp_int を FreeBASIC Integer に型変換することは"
Print "gmp_int が Integer に収まることがわかっている場合にだけ、使えます"

k = two
Print "k = two ->";k

Print
i = "1" + String(35, "0") 
i = i + 1
Print i; " / 3 = "; i / 3
Print
Print 
Print "19 shr 1 = " ; 19 shr 1 
Print "gmp_int_2_base(19,2) " ; gmp_int_2_base(19,2)
Print "gmp_int_2_base(9,2)  " ; gmp_int_2_base(9,2)
Print 
Print "19 shl 1 = " ; 19 shl 1 
Print "gmp_int_2_base(19,2) " ; gmp_int_2_base(19,2)
Print "gmp_int_2_base(38,2) " ; gmp_int_2_base(38,2)
Print

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

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

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

Print
Print "gmp_int_2_base を使って、gmp_int 数を、文字列として出力する"
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

'*********************************
' 平方根 n乗根

Print
i = 10000
Print i; " の平方根(小数切り捨て) ";" = "; root(i)
Print "残余 = "; rootrem(i)
Print
Print i; " の5乗根(小数切り捨て)";" = "; root(i, 5)
Print "残余 = "; rootrem(i, 5)
Print root(i, 5); " ^ 5 = "; root(i, 5) ^ 5
Print root(i, 5) ^ 5; " + "; rootrem(i, 5); " = ";
Print root(i, 5) ^ 5 + rootrem(i ,5); ", i = "; i
Print
Print "62の3乗根 " , "root(62, 3) = "; root(62, 3)
Print

i = 40
Print "     開始値 "; gmp_int_2_base(i, 2)
setbit (i, 0)
Print "  set bit 0 "; gmp_int_2_base(i, 2)
clrbit (i, 0)
Print "clear bit 0 "; gmp_int_2_base(i, 2)
combit (i, 1)
Print " 補数 bit 1 "; gmp_int_2_base(i, 2)
combit (i, 1)
Print " 補数 bit 1 "; gmp_int_2_base(i, 2)
Print

For k = 0 To 5
    Print "bit"; k;
    If tstbit(i, k) = 0 Then Print " is 0"
    If tstbit(i, k) = 1 Then Print " is 1"
Next

Print
Sleep
' 素数

i = 10
Print i; " ^ 2 mod 49 = "; powm(i, 2, 49)

Print
Print i;
k = isprime(i)
If k = 2 Then
    Print " 素数"
ElseIf k = 1 Then
    Print " おそらく素数(特定されていない)"
ElseIf k = 0 Then
    Print " 素数でない"
End If

Print
i = 2 : i = i ^ 61 -1 ' メルセンヌ数、2の冪よりも 1 小さい自然数
Print i; " , 15 回テスト (既定)";
k = isprime(i)
If k = 2 Then
Print " 素数"
ElseIf k = 1 Then
    Print " おそらく素数(特定されていない)"
ElseIf k = 0 Then
    Print " 素数でない"
End If

Print i; " , 50 回テスト,";
k = isprime(i , 50)
If k = 2 Then
    Print " 素数"
ElseIf k = 1 Then
    Print " おそらく素数(特定されていない)"
ElseIf k = 0 Then
    Print " 素数でない"
End If

Print
Print i; ", 次の素数 = "; nextprime(i)

Print

i = "11111111111111111111111"
Print i; " , 1000 回テスト,";
k = isprime(i , 1000)
If k = 2 Then
    Print " 素数"
ElseIf k = 1 Then
    Print " おそらく素数(特定されていない)"
ElseIf k = 0 Then
    Print " 素数でない"
End If
Print

i = "111111111111111111131111111111111111111"
Print i; " , 1000 回テスト,";
k = isprime(i , 1000)
If k = 2 Then
    Print " 素数"
ElseIf k = 1 Then
    Print " おそらく素数(特定されていない)"
ElseIf k = 0 Then
    Print " 素数でない"
End If
Sleep
Print
'*********************************
' 加算、減算

Print "変数に整数を入力する方法"

Dim As gmp_int c
Print
Dim As gmp_int a = "123456789123456789123456789123456789123456789123456789" 
Dim As gmp_int b = "987654321987654321987654321987654321987654321987654321"
c = a + b +1
Print c
Print gmp_int_2_base(c, 62); " (base 62)"

Print
c = a
c += b +1 
Print c

Print 
c = 2
c ^= 128
Print c
Print
Print "整数を直接計算する方法"
Print
Print  gmp_int("123456789012345678901234567890123456789012345678901234567890")-gmp_int("123456789012345678901234567890")+1
Print
Print
' 最大公約数、最小公倍数

i = 20 : j = 100
Print "最大公約数 gcd("; i; ", "; j; ") = "; gcd(i, j) 
Print "最小公倍数 lcm("; i; ", "; j; ") = "; lcm(i, j) 
Print
i = "1234567890123456789" : j = "2345612345623456123456"
Print "最大公約数 gcd("; i; ", "; j; ") = "; gcd(i, j)
Print "最小公倍数 lcm("; i; ", "; j; ") = "; lcm(i, j)  
Print
Print "123456789012345678901234567890123456789012345678901234567890 と 123456789012345678901234567890 の最大公約数は "
Print gcd(gmp_int("123456789012345678901234567890123456789012345678901234567890"), gmp_int("123456789012345678901234567890"))

Print 
' 階乗

Print "階乗 fac(10) = "; fac(10)
Print "多重階乗 mfac(n, m)  = n!^(m) = n*(n-m)*(n-2m)*... "
Print "多重階乗、7 飛ばしの積 mfac(10, 7) = "; mfac(10, 7) ' 10 * 3

Print
Print "素数積、10 以下のすべての正の素数の積 primorial(10) = "; primorial(10) ' 2 * 3 * 5 * 7

Print
Print "100 番目のフィボナッチ数 = "; fib(100)
Print

Sleep
' 乱数

Print "乱数"

Dim As gmp_int array(1 To 2, 1 To 10)

For k = 1 To 10
    array(1, k) = gmp_rnd(10)
    array(2, k) = gmp_rnd  ' 0 〜 2^32-1 の間の数を返す
Next

For k = 1 To 10
    Print array(1, k), array(2, k)
Next


Print 
'整形して出力するために GMP 表示ルーチンを使う
'Gmp_printf( !"%Zd\n", c.num )
Gmp_printf( !"%70Zd\n", c.num )  ' 右詰め70文字。 幅は空白で埋める
Gmp_printf( !"%070Zd\n", c.num ) ' 右詰め70文字。 幅はゼロで埋める


Print : Print "デモ終了"


Sleep
End

解説:
gmp_int ( ByRef s As String, ByVal _base As Integer = 10 )
2つめの引数として、基数 2〜62 の数字を入力できます。既定値= 10(10進数)です。
例:
Dim As gmp_int i
i = gmp_int("1234") = gmp_int("1234", 10) = "1234"
i = gmp_int("abcd", 16) ' 16進数
i = gmp_int("1001", 2) ' 2進数
i = gmp_int("7777", 8) ' 8進数


gmp_int_2_base (ByRef bigint As gmp_int, ByVal _base As Integer = 10 ) As String
基数 2 〜 62(デフォルト10、10進数)の gmp_int 数を文字列に変換したものを返します。

gmp_int.bi

' version 22/05/2017

'by frisian on May 22, 2017 21:09
'https://www.freebasic.net/forum/viewtopic.php?f=7&t=25684

' オリジナル by yetifoot
'https://www.freebasic.net/forum/viewtopic.php?t=7173

' May 2017: srvaldez
' ループコードを修正

' May 2017: frisian
' 自己責任でお使い下さい
' 注意: このファイルを動かすためには GMP 6.0 32bit が必要です(テスト済み)。
'       GMP 4.0 では動作しません(一部の関数は後で追加された)
'       GMP 5.0 ではテストしていません
'
' mpz_mod を mpz_tdiv_r に変更して、mod がデフォルトの FB動作を模倣するようにしました。
' \(整数除算)と mod の両方で tdiv(切り捨て)
' この動作は、あなたが FB の float 扱いを integer 変換に変更しても、変わりません
' 「ceil 天井」は切り上げ、「floor 床」は切捨て、「round」は四捨五入した結果を返します
' 結果を切捨て(floor) にしたい場合は、mpz_fdiv を使います
' 結果を切り上げ(ceil) にしたい場合は、mpz_cdiv を使います
'
' 浮動小数点の除算(/)から余りを得るには、学校で習った算術が必要です
' remainder = number - (number / divisor) * divisor
'
' 配列と型を作成できます
' swap も機能します
'
' 浮動小数点除算(/)を修正・改良
' 追加演算子 Shr(SHift Right 右ビットシフト) と Shl(Shift Left 左ビットシフト) を追加

' コメントのいくつかの誤りを修正し、リストを整理
' 関数 gmp_int_2_base(gmp_int、n = 2)を追加。基数 2 〜 62 (既定は 10、10進数) の gmp_int 数の文字列を返す
' setbit(gmp_int、n)を追加 (n番目のビットを1に設定)
' clrbit(gmp_int、n)を追加 (n番目のビットを0に設定)
' combit (gmp_int、n) を追加 (n番目のビットを反転 (1 -> 0, 0 -> 1))
' tstbit (gmp_int, n) を追加 (n番目のビットをテストし、そのビット (0 または 1) を返す)
' root (gmp_int, n = 2) を追加 (default = 2, 平方根) (n次元 root の小数を切り捨てた整数部分を返す)
'     root (gmp_int, 3) は立方根
' rootrem (gmp_int, n = 2) を追加 (gmp_int - root(gmp_int, n) ^ n を返す)
' powm (gmp_int1, n, gmp_int2) を追加 ((gmp_int1 ^ n) mod gmp_int2 を返す)
' isprime (gmp_int, reps) を追加
'              (n が確実に素数なら 2 を返す
'               n がおそらく素数なら 1 を返す(特定されていない場合)
'               n が確実に素数でないなら 0 を返す
'               reps の妥当な値は 15〜50 です(デフォルト= 15))
' nextprime (gmp_int) を追加 (gmp_int より大きい次の素数を見つける)
' legendre (gmp_int1, gmp_int2) を追加 (ルジャンドル記号 (-1、0、1)を返す)
'               ルジャンドル記号とは、a が p の平方剰余か否かを簡潔に表す記号
' gcd (gmp_int1, gmp_int2) を追加 (最大公約数を返す)
' lcm (gmp_int1, gmp_int2) を追加 (最小公倍数を返す)
' fac (n) を追加 (階乗 n! を返す)
' mfac (n, m) を追加 (m 多重階乗を返す。m 飛ばしの積、n!^(m) = n*(n-m)*(n-2m)*...)
' primorial (n) を追加 (素数積、<= n のすべての正の素数の積を返す)
' fib (n) を追加 (n 番目のフィボナッチ数を返す)
'
' rnd (gmp_int) を追加 (擬似乱数列生成器メルセンヌ・ツイスタ、0 と gmp_int - 1 の間の乱数を返す)
'                       数を指定ししないか、数 <= 0 の場合は、数は 2 ^ 32 に設定されます。
'                       ルーチンが最初に呼び出されたとき、乱数生成器は種設定されます。
' タイマーを無作為化すると、毎回種が変わります
' 無作為化を使わないか、または無作為化「数」を実行すると、連続して起こる結果は同じになります(FB rnd と同じ)
'
' setbit, clrbit, combit は値を返しません
' tstbit, gmp_sgn, isprime, legendre は long を返します
' root, rootrem, powm, nextprime, gcd, lcm, fac, mfac, primorial, fib, gmp_rnd は、gmp_int を返す
'
' 多重定義演算子 +=, -=, *=, \=, /=, ^=, Mod=, And=, Or=, Xor=, Shl= ans Shr= to は、gmp_int で動作します
'
' 多重定義 abs(), sgn() は gmp_int で動作します


#Ifndef __GMP_INT_BI__
#Define __GMP_INT_BI__

#Include Once "gmp.bi"

Type gmp_int
    Declare Constructor ( )
    Declare Constructor ( ByVal i As Long )
    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 Long)
    Declare Operator Let ( ByRef s As String )
    Declare Operator Cast ( ) As Long
    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 Long = 10 ) As String
    num As mpz_ptr = 0

    Declare Operator += (ByRef rhs As gmp_int)
    Declare Operator -= (ByRef rhs As gmp_int)
    Declare Operator *= (ByRef rhs As gmp_int)
    Declare Operator \= (ByRef rhs As gmp_int)
    Declare Operator /= (ByRef rhs As gmp_int)
    Declare Operator ^= (ByVal rhs As Long)
    Declare Operator Mod= (ByRef rhs As gmp_int)
    Declare Operator And= (ByRef rhs As gmp_int)
    Declare Operator Or= (ByRef rhs As gmp_int)
    Declare Operator Xor= (ByRef rhs As gmp_int)
    Declare Operator Shl= (ByVal rhs As Long)
    Declare Operator Shr= (ByVal rhs As Long)

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 Function root ( ByRef op As gmp_int, ByVal n As Long = 2 ) As gmp_int
Declare Function rootrem ( ByRef op As gmp_int, ByVal n As Long = 2 ) As gmp_int
Declare Operator ^ ( ByRef lhs As gmp_int, ByVal rhs As Long ) As gmp_int
Declare Operator Mod ( ByRef lhs As gmp_int, ByRef rhs As gmp_int ) As gmp_int
Declare Function powm (ByRef op As gmp_int, ByRef power As gmp_int, ByRef modulus 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 Long ) As gmp_int
Declare Operator Shr ( ByRef lhs As gmp_int, ByVal rhs As Long ) As gmp_int
Declare Operator Sgn ( ByRef rhs As gmp_int ) As Long
Declare Operator Abs ( ByRef rhs As gmp_int ) As gmp_int
Declare Sub setbit ( ByRef op As gmp_int, ByVal n As Long )
Declare Sub clrbit ( ByRef op As gmp_int, ByVal n As Long )
Declare Sub combit ( ByRef op As gmp_int, ByVal n As Long )
Declare Function tstbit ( ByRef op As gmp_int, ByVal n As Long ) As Long
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 Long
Declare Operator < ( ByRef lhs As gmp_int, ByRef rhs As gmp_int ) As Long
Declare Operator > ( ByRef lhs As gmp_int, ByRef rhs As gmp_int ) As Long
Declare Operator <= ( ByRef lhs As gmp_int, ByRef rhs As gmp_int ) As Long
Declare Operator >= ( ByRef lhs As gmp_int, ByRef rhs As gmp_int ) As Long
Declare Operator <> ( ByRef lhs As gmp_int, ByRef rhs As gmp_int ) As Long
Declare Function gmp_int_2_base (ByRef bigint As gmp_int, ByVal _base As Long = 10 ) As String
Declare Function isprime ( ByRef op As gmp_int, ByVal reps As Long = 15 ) As Long
Declare Function nextprime ( ByRef op As gmp_int ) As gmp_int
Declare Function legendre ( ByRef a As gmp_int , ByRef p As gmp_int ) As Long
Declare Function gcd ( ByRef a As gmp_int, ByRef b As gmp_int ) As gmp_int
Declare Function lcm ( ByRef a As gmp_int, ByRef b As gmp_int ) As gmp_int
Declare Function fac (ByVal n As Long ) As gmp_int
Declare Function mfac (ByVal n As Long, ByVal m As Long ) As gmp_int ' result = n!^(m) = n*(n-m)*(n-2m)*...
Declare Function primorial (ByVal n As Long ) As gmp_int
Declare Function fib ( ByVal n As Long ) As gmp_int
Declare Function gmp_rnd ( ByRef max As gmp_int = 0) As gmp_int

#EndIf '__GMP_INT_BI__

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

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

End Constructor

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

num = Callocate( SizeOf( __mpz_struct ) )
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 ) )
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 Long )

    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 Long
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 Long = 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

    ' これは実際に非常に厄介ですが、浮動小数割り算で思いつくことができる最善の方法です、
    ' 丸めは人々が期待する結果をもたらします。
    ' 0.5 は 1 に、0.4 は 0 に、-0.5 は -1 に、-0.4 は 0 になります。
    ' temp が必要な 100% ではありませんが、それを安全のために使いました。
    ' 一部の GMP 関数では、mpz を dest として、また source のひとつとして渡すことは、悪い考えです。

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

    'gmp 浮動小数点のサイズが固定されていると、精度が低下する可能性があります
    'サイズは mpf_set_default_prec によって、または mpf_init2('var'、size) を使って設定されます
    'lhs と rhs のサイズを見つけ、最長のサイズをとり、32ビット(9桁)加えます

    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 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

    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

Function root ( ByRef op As gmp_int, ByVal n As Long = 2 ) As gmp_int

    Dim As gmp_int result

    mpz_root( result.num, op.num, n )

    Function = result

End Function

Function rootrem ( ByRef op As gmp_int, ByVal n As Long = 2 ) As gmp_int

    Dim As gmp_int result, tmp

    mpz_rootrem( tmp.num, result.num, op.num, n )

    Function = result

End Function

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

    Dim As gmp_int result

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

    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_tdiv_r( result.num, lhs.num, rhs.num )

    Operator = result

End Operator

Function powm ( ByRef _base As gmp_int, ByRef power As gmp_int, ByRef modulus As gmp_int ) As gmp_int

    Dim As gmp_int result

    mpz_powm( result.num, _base.num, power.num, modulus.num )

    Return result

End Function

'::::::::
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 Long ) 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 Long ) As gmp_int

    Dim As gmp_int result

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

    Operator = result

End Operator

Operator Sgn ( ByRef rhs As gmp_int ) As Long

    Return mpz_sgn( rhs.num )

End Operator

Operator Abs ( ByRef rhs As gmp_int ) As gmp_int

    Dim As gmp_int result

    mpz_abs(result.num, rhs.num )

    Return result

End Operator

Sub setbit ( ByRef op As gmp_int, ByVal n As Long)

    mpz_setbit( op.num, n )

End Sub

Sub clrbit ( ByRef op As gmp_int, ByVal n As Long)

    mpz_clrbit( op.num, n )

End Sub

Sub combit ( ByRef op As gmp_int, ByVal n As Long)

    mpz_combit( op.num, n )

End Sub

Function tstbit ( ByRef op As gmp_int, ByVal n As Long) As Long
    ' return 0 if the bit is 0 and 1 if the bit is 1
    Return mpz_tstbit( op.num, n )

End Function

'::::::::
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 Long

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

End Operator

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

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

End Operator

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

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

End Operator

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

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

End Operator

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

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

End Operator

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

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

End Operator

Operator gmp_int.+= (ByRef rhs As gmp_int)
    mpz_add(This.num, this.num, rhs.num)
End Operator

Operator gmp_int.-= (ByRef rhs As gmp_int)
    mpz_sub(This.num, this.num, rhs.num)
End Operator

Operator gmp_int.*= (ByRef rhs As gmp_int)
    mpz_mul(This.num, this.num, rhs.num)
End Operator

Operator gmp_int.\= (ByRef rhs As gmp_int)
    mpz_tdiv_q(This.num, this.num, rhs.num)
End Operator

Operator gmp_int./= (ByRef rhs As gmp_int)
    This = This / rhs
End Operator

Operator gmp_int.^= (ByVal rhs As Long)
    mpz_pow_ui(This.num, this.num, rhs)
End Operator

Operator gmp_int.mod= (ByRef rhs As gmp_int)
    mpz_tdiv_r( this.num, this.num, rhs.num )
End Operator

Operator gmp_int.And= (ByRef rhs As gmp_int)
    mpz_and(This.num, this.num, rhs.num)
End Operator

Operator gmp_int.Or= (ByRef rhs As gmp_int)
    mpz_ior(This.num, this.num, rhs.num)
End Operator

Operator gmp_int.Xor= (ByRef rhs As gmp_int)
    mpz_xor(This.num, this.num, rhs.num)
End Operator

Operator gmp_int.shl= (ByVal rhs As Long)
    mpz_mul_2exp(This.num, this.num, rhs)
End Operator

Operator gmp_int.Shr= (ByVal rhs As Long)
    mpz_tdiv_q_2exp(This.num, this.num, rhs)
End Operator

' 基数 2 〜 62(デフォルト10、10進数)の gmp_int 数の文字列を返します。
Function gmp_int_2_base (ByRef bigint As gmp_int, ByVal _base As Long = 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

Function isprime ( ByRef op As gmp_int, ByVal reps As Long = 15 ) As Long
    ' n が確実に素数なら 2 を返す
    ' n がおそらく素数なら 1 を返す(特定されていない場合)
    ' n が確実に素数でないなら 0 を返す
    ' reps の妥当な値は 15〜50 です(デフォルト= 15))

    If reps < 15 Then reps = 15

    Function = mpz_probab_prime_p ( op.num, reps )

End Function

Function nextprime ( ByRef op As gmp_int ) As gmp_int

    Dim As gmp_int result

    mpz_nextprime( result.num , op.num)

    Function = result

End Function

Function legendre (ByRef a As gmp_int , ByRef p As gmp_int ) As Long
    ' p needs to be a odd positive prime
    Function = mpz_legendre ( a.num, p.num)

End Function

Function gcd ( ByRef a As gmp_int, ByRef b As gmp_int ) As gmp_int

    Dim As gmp_int result

    mpz_gcd( result.num, a.num, b.num )

    Function = result

End Function

Function lcm ( ByRef a As gmp_int, ByRef b As gmp_int ) As gmp_int

    Dim As gmp_int result

    mpz_lcm( result.num, a.num, b.num )

    Function = result

End Function

Function fac (ByVal n As Long ) As gmp_int

    Dim As gmp_int result

    mpz_fac_ui( result.num , n )

    Function = result

End Function

Function mfac (ByVal n As Long, ByVal m As Long ) As gmp_int
    ' result = n!^(m) = n*(n-m)*(n-2m)*...
    Dim As gmp_int result

    mpz_mfac_uiui ( result.num, n, m )

    Function = result

End Function

Function primorial (ByVal n As Long ) As gmp_int

    Dim As gmp_int result

    mpz_primorial_ui (result.num, n )

    Function = result

End Function

Function fib ( ByVal n As Long ) As gmp_int

    Dim As gmp_int result

    mpz_fib_ui ( result.num, n)

    Function  = result

End Function

' -= Random number generator stuff (integer) =-
Type gmp_random
    Declare Constructor ( )
    Declare Destructor ( )
    g_rnd As Any Ptr
End Type

Constructor gmp_random ( )

   g_rnd = Callocate( SizeOf ( __gmp_randstate_struct ) )
   gmp_randinit_mt ( g_rnd )   ' Mersenne Twister

End Constructor

Destructor gmp_random ( )

   gmp_randclear ( g_rnd )
   DeAllocate ( g_rnd )

End Destructor

Function gmp_rnd ( ByRef max As gmp_int = 0 ) As gmp_int

    Static state As gmp_random
    Static flag As Long

    If flag = 0 Then

        Dim As String seed_str
        Dim As gmp_int seed

        For i As Long = 0 To 200 ' create seed
            seed_str += Str( Int( Rnd * 10 ) )
        Next

        seed = seed_str
        Gmp_randseed ( state.g_rnd, seed.num )   ' seed the random generator

        flag = 1

    End If

    If max <= 0 Then
        max = 2
        max ^= 32        ' 2 ^ 32
    End If
    Dim As gmp_int result
    Mpz_urandomm ( result.num , state.g_rnd, max.num )

    Function = result

End Function
 
補足 に戻る
←リンク元に戻る プログラム開発関連に戻る
ページ歴史:2017-05-26
日本語翻訳:WATANABE Makoto、原文著作者:yetifoot、srvaldez、frisian , 2017-05-22 21:09

ホームページのトップに戻る

表示-非営利-継承