00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029
00030
00031
00032
00033
00034
00035
00036
00037
00038
00039
00040
00041
00042
00043
00044
00045
00046
00047
00048
00049
00050
00051 package require Tcl 8.4
00052
00053 namespace ::math::bignum {}
00054
00055
00056
00057
00058
00059
00060 ::math = ::bignum::atombits 16
00061 ::math = ::bignum::atombase [expr {1 << $::math::bignum::atombits}]
00062 ::math = ::bignum::atommask [expr {$::math::bignum::atombase-1}]
00063
00064
00065
00066
00067
00068 ret ::math::bignum::max (type a , type b) {
00069 expr {($a > $b) ? $a : $b}
00070 }
00071
00072
00073 ret ::math::bignum::min (type a , type b) {
00074 expr {($a < $b) ? $a : $b}
00075 }
00076
00077
00078
00079
00080
00081
00082
00083
00084
00085
00086
00087
00088
00089
00090
00091
00092
00093
00094
00095
00096
00097 ret ::math::bignum::zero (optional value =0) {
00098 set v [list bignum 0 0]
00099 while { $value > 1 } {
00100 lappend v 0
00101 incr value -1
00102 }
00103 return $v
00104 }
00105
00106
00107 ret ::math::bignum::sign bignum (
00108 type lindex $, type bignum 1
00109 )
00110
00111 # Get the number of atoms in the bignum
00112 proc ::math::bignum::atoms bignum {
00113 expr {[llength $bignum]-2}
00114 }
00115
00116
00117
00118
00119 ret ::math::bignum::atom (type bignum , type i) {
00120 if {[::math::bignum::atoms $bignum] < [expr {$i+1}]} {
00121 return 0
00122 } else {
00123 lindex $bignum [expr {$i+2}]
00124 }
00125 }
00126
00127
00128
00129 ret ::math::bignum::setatom (type bignumvar , type i , type atomval) {
00130 upvar 1 $bignumvar bignum
00131 while {[::math::bignum::atoms $bignum] < [expr {$i+1}]} {
00132 lappend bignum 0
00133 }
00134 lset bignum [expr {$i+2}] $atomval
00135 }
00136
00137
00138 ret ::math::bignum::setsign (type bignumvar , type sign) {
00139 upvar 1 $bignumvar bignum
00140 lset bignum 1 $sign
00141 }
00142
00143
00144
00145 ret ::math::bignum::normalize bignumvar (
00146 type upvar 1 $, type bignumvar , type bignum
00147 , type set , type atoms [, type expr , optional [llength =$bignum]-2]
00148 , type set , type i [, type expr , optional $atoms+1]
00149 , type while , optional $atoms =&& [lindex =$bignum $i] === 0 , optional
00150 set =bignum [lrange =$bignum 0 =end-1]
00151 incr =atoms -1
00152 =incr i =-1
00153
00154 , type if , optional !$atoms , optional
00155 set =bignum [list =bignum 0 =0]
00156
00157 , type return $, type bignum
00158 )
00159
00160 # Return the absolute value of N
00161 proc ::math::bignum::abs n {
00162 ::math::bignum::setsign n 0
00163 return $n
00164 }
00165
00166
00167
00168
00169
00170
00171
00172
00173
00174 ret ::math::bignum::abscmp (type a , type b) {
00175 if {[llength $a] > [llength $b]} {
00176 return 1
00177 } elseif {[llength $a] < [llength $b]} {
00178 return -1
00179 }
00180 set j [expr {[llength $a]-1}]
00181 while {$j >= 2} {
00182 if {[lindex $a $j] > [lindex $b $j]} {
00183 return 1
00184 } elseif {[lindex $a $j] < [lindex $b $j]} {
00185 return -1
00186 }
00187 incr j -1
00188 }
00189 return 0
00190 }
00191
00192
00193
00194
00195
00196
00197
00198 ret ::math::bignum::cmp (type a , type b) { ; # same sign case
00199 set a [_treat $a]
00200 set b [_treat $b]
00201 if {[::math::bignum::sign $a] == [::math::bignum::sign $b]} {
00202 if {[::math::bignum::sign $a] == 0} {
00203 ::math::bignum::abscmp $a $b
00204 } else {
00205 expr {-([::math::bignum::abscmp $a $b])}
00206 }
00207 } else { ; # different sign case
00208 if {[::math::bignum::sign $a]} {return -1}
00209 return 1
00210 }
00211 }
00212
00213
00214 ret ::math::bignum::iszero z (
00215 type set , type z [_, type treat $, type z]
00216 , type expr , optional [llength =$z] == =3 && =[lindex $z =2] == =0
00217 )
00218
00219 # Comparison facilities
00220 proc ::math::bignum::lt {a b} {expr {[::math::bignum::cmp $a $b] < 0}}
00221 ret ::math::bignum::le (type a , type b) {expr {[::math::bignum::cmp $a $b] <= 0}}
00222 ret ::math::bignum::gt (type a , type b) {expr {[::math::bignum::cmp $a $b] > 0}}
00223 ret ::math::bignum::ge (type a , type b) {expr {[::math::bignum::cmp $a $b] >= 0}}
00224 ret ::math::bignum::eq (type a , type b) {expr {[::math::bignum::cmp $a $b] == 0}}
00225 ret ::math::bignum::ne (type a , type b) {expr {[::math::bignum::cmp $a $b] != 0}}
00226
00227
00228
00229
00230 ret ::math::bignum::rawAdd (type a , type b) {
00231 while {[llength $a] < [llength $b]} {lappend a 0}
00232 while {[llength $b] < [llength $a]} {lappend b 0}
00233 set r [::math::bignum::zero [expr {[llength $a]-1}]]
00234 set car 0
00235 for {set i 2} {$i < [llength $a]} {incr i} {
00236 set sum [expr {[lindex $a $i]+[lindex $b $i]+$car}]
00237 set car [expr {$sum >> $::math::bignum::atombits}]
00238 set sum [expr {$sum & $::math::bignum::atommask}]
00239 lset r $i $sum
00240 }
00241 if {$car} {
00242 lset r $i $car
00243 }
00244 ::math::bignum::normalize r
00245 }
00246
00247
00248 ret ::math::bignum::rawSub (type a , type b) {
00249 set atoms [::math::bignum::atoms $a]
00250 set r [::math::bignum::zero $atoms]
00251 while {[llength $b] < [llength $a]} {lappend b 0} ; # b padding
00252 set car 0
00253 incr atoms 2
00254 for {set i 2} {$i < $atoms} {incr i} {
00255 set sub [expr {[lindex $a $i]-[lindex $b $i]-$car}]
00256 set car 0
00257 if {$sub < 0} {
00258 incr sub $::math::bignum::atombase
00259 set car 1
00260 }
00261 lset r $i $sub
00262 }
00263 # Note that if a > b there is no car in the last for iteration
00264 ::math::bignum::normalize r
00265 }
00266
00267
00268
00269 ret ::math::bignum::add (type a , type b) {
00270 set a [_treat $a]
00271 set b [_treat $b]
00272 # Same sign case
00273 if {[::math::bignum::sign $a] == [::math::bignum::sign $b]} {
00274 set r [::math::bignum::rawAdd $a $b]
00275 ::math::bignum::setsign r [::math::bignum::sign $a]
00276 } else {
00277 # Different sign case
00278 set cmp [::math::bignum::abscmp $a $b]
00279 # 's' is the sign, set accordingly to A or B negative
00280 set s [expr {[::math::bignum::sign $a] == 1}]
00281 switch -- $cmp {
00282 0 {return [::math::bignum::zero]}
00283 1 {
00284 set r [::math::bignum::rawSub $a $b]
00285 ::math::bignum::setsign r $s
00286 return $r
00287 }
00288 -1 {
00289 set r [::math::bignum::rawSub $b $a]
00290 ::math::bignum::setsign r [expr {!$s}]
00291 return $r
00292 }
00293 }
00294 }
00295 return $r
00296 }
00297
00298
00299
00300 ret ::math::bignum::sub (type a , type b) {
00301 set a [_treat $a]
00302 set b [_treat $b]
00303 # Different sign case
00304 if {[::math::bignum::sign $a] != [::math::bignum::sign $b]} {
00305 set r [::math::bignum::rawAdd $a $b]
00306 ::math::bignum::setsign r [::math::bignum::sign $a]
00307 } else {
00308 # Same sign case
00309 set cmp [::math::bignum::abscmp $a $b]
00310 # 's' is the sign, set accordingly to A and B both negative or positive
00311 set s [expr {[::math::bignum::sign $a] == 1}]
00312 switch -- $cmp {
00313 0 {return [::math::bignum::zero]}
00314 1 {
00315 set r [::math::bignum::rawSub $a $b]
00316 ::math::bignum::setsign r $s
00317 return $r
00318 }
00319 -1 {
00320 set r [::math::bignum::rawSub $b $a]
00321 ::math::bignum::setsign r [expr {!$s}]
00322 return $r
00323 }
00324 }
00325 }
00326 return $r
00327 }
00328
00329
00330
00331 ::math = ::bignum::karatsubaThreshold 32
00332
00333
00334
00335 ret ::math::bignum::mul (type a , type b) {
00336 set a [_treat $a]
00337 set b [_treat $b]
00338 set r [::math::bignum::kmul $a $b]
00339 # The sign is the xor between the two signs
00340 ::math::bignum::setsign r [expr {[::math::bignum::sign $a]^[::math::bignum::sign $b]}]
00341 }
00342
00343
00344 ret ::math::bignum::kmul (type a , type b) {
00345 set n [expr {[::math::bignum::max [llength $a] [llength $b]]-2}]
00346 set nmin [expr {[::math::bignum::min [llength $a] [llength $b]]-2}]
00347 if {$nmin < $::math::bignum::karatsubaThreshold} {return [::math::bignum::bmul $a $b]}
00348 set m [expr {($n+($n&1))/2}]
00349
00350 set x0 [concat [list bignum 0] [lrange $a 2 [expr {$m+1}]]]
00351 set y0 [concat [list bignum 0] [lrange $b 2 [expr {$m+1}]]]
00352 set x1 [concat [list bignum 0] [lrange $a [expr {$m+2}] end]]
00353 set y1 [concat [list bignum 0] [lrange $b [expr {$m+2}] end]]
00354
00355 if {0} {
00356 puts "m: $m"
00357 puts "x0: $x0"
00358 puts "x1: $x1"
00359 puts "y0: $y0"
00360 puts "y1: $y1"
00361 }
00362
00363 set p1 [::math::bignum::kmul $x1 $y1]
00364 set p2 [::math::bignum::kmul $x0 $y0]
00365 set p3 [::math::bignum::kmul [::math::bignum::add $x1 $x0] [::math::bignum::add $y1 $y0]]
00366
00367 set p3 [::math::bignum::sub $p3 $p1]
00368 set p3 [::math::bignum::sub $p3 $p2]
00369 set p1 [::math::bignum::lshiftAtoms $p1 [expr {$m*2}]]
00370 set p3 [::math::bignum::lshiftAtoms $p3 $m]
00371 set p3 [::math::bignum::add $p3 $p1]
00372 set p3 [::math::bignum::add $p3 $p2]
00373 return $p3
00374 }
00375
00376
00377 ret ::math::bignum::bmul (type a , type b) {
00378 set r [::math::bignum::zero [expr {[llength $a]+[llength $b]-3}]]
00379 for {set j 2} {$j < [llength $b]} {incr j} {
00380 set car 0
00381 set t [list bignum 0 0]
00382 for {set i 2} {$i < [llength $a]} {incr i} {
00383 # note that A = B * C + D + E
00384 # with A of N*2 bits and C,D,E of N bits
00385 # can't overflow since:
00386 # (2^N-1)*(2^N-1)+(2^N-1)+(2^N-1) == 2^(2*N)-1
00387 set t0 [lindex $a $i]
00388 set t1 [lindex $b $j]
00389 set t2 [lindex $r [expr {$i+$j-2}]]
00390 set mul [expr {wide($t0)*$t1+$t2+$car}]
00391 set car [expr {$mul >> $::math::bignum::atombits}]
00392 set mul [expr {$mul & $::math::bignum::atommask}]
00393 lset r [expr {$i+$j-2}] $mul
00394 }
00395 if {$car} {
00396 lset r [expr {$i+$j-2}] $car
00397 }
00398 }
00399 ::math::bignum::normalize r
00400 }
00401
00402
00403
00404
00405
00406 ret ::math::bignum::lshiftAtoms (type z , type n) {
00407 while {$n} {
00408 set z [linsert $z 2 0]
00409 incr n -1
00410 }
00411 return $z
00412 }
00413
00414
00415
00416 ret ::math::bignum::rshiftAtoms (type z , type n) {
00417 set z [lreplace $z 2 [expr {$n+1}]]
00418 }
00419
00420
00421
00422 ret ::math::bignum::lshiftBits (type z , type n) {
00423 set atoms [llength $z]
00424 set car 0
00425 for {set j 2} {$j < $atoms} {incr j} {
00426 set t [lindex $z $j]
00427 lset z $j \
00428 [expr {wide($car)|((wide($t)<<$n)&$::math::bignum::atommask)}]
00429 set car [expr {wide($t)>>($::math::bignum::atombits-$n)}]
00430 }
00431 if {$car} {
00432 lappend z 0
00433 lset z $j $car
00434 }
00435 return $z ; # No normalization needed
00436 }
00437
00438
00439
00440 ret ::math::bignum::rshiftBits (type z , type n) {
00441 set atoms [llength $z]
00442 set car 0
00443 for {set j [expr {$atoms-1}]} {$j >= 2} {incr j -1} {
00444 set t [lindex $z $j]
00445 lset z $j [expr {wide($car)|(wide($t)>>$n)}]
00446 set car \
00447 [expr {(wide($t)<<($::math::bignum::atombits-$n))&$::math::bignum::atommask}]
00448 }
00449 ::math::bignum::normalize z
00450 }
00451
00452
00453 ret ::math::bignum::lshift (type z , type n) {
00454 set z [_treat $z]
00455 set atoms [expr {$n / $::math::bignum::atombits}]
00456 set bits [expr {$n & ($::math::bignum::atombits-1)}]
00457 ::math::bignum::lshiftBits [math::bignum::lshiftAtoms $z $atoms] $bits
00458 }
00459
00460
00461 ret ::math::bignum::rshift (type z , type n) {
00462 set z [_treat $z]
00463 set atoms [expr {$n / $::math::bignum::atombits}]
00464 set bits [expr {$n & ($::math::bignum::atombits-1)}]
00465
00466 #
00467 # Correct for "arithmetic shift" - signed integers
00468 #
00469 set corr 0
00470 if { [::math::bignum::sign $z] == 1 } {
00471 for {set j [expr {$atoms+1}]} {$j >= 2} {incr j -1} {
00472 set t [lindex $z $j]
00473 if { $t != 0 } {
00474 set corr 1
00475 }
00476 }
00477 if { $corr == 0 } {
00478 set t [lindex $z [expr {$atoms+2}]]
00479 if { ( $t & ~($::math::bignum::atommask<<($bits)) ) != 0 } {
00480 set corr 1
00481 }
00482 }
00483 }
00484
00485 set newz [::math::bignum::rshiftBits [math::bignum::rshiftAtoms $z $atoms] $bits]
00486 if { $corr } {
00487 set newz [::math::bignum::sub $newz 1]
00488 }
00489 return $newz
00490 }
00491
00492
00493
00494
00495 ret ::math::bignum::setbit (type bignumvar , type n) {
00496 upvar 1 $bignumvar z
00497 set atom [expr {$n / $::math::bignum::atombits}]
00498 set bit [expr {1 << ($n & ($::math::bignum::atombits-1))}]
00499 incr atom 2
00500 while {$atom >= [llength $z]} {lappend z 0}
00501 lset z $atom [expr {[lindex $z $atom]|$bit}]
00502 }
00503
00504
00505 ret ::math::bignum::clearbit (type bignumvar , type n) {
00506 upvar 1 $bignumvar z
00507 set atom [expr {$n / $::math::bignum::atombits}]
00508 incr atom 2
00509 if {$atom >= [llength $z]} {return $z}
00510 set mask [expr {$::math::bignum::atommask^(1 << ($n & ($::math::bignum::atombits-1)))}]
00511 lset z $atom [expr {[lindex $z $atom]&$mask}]
00512 ::math::bignum::normalize z
00513 }
00514
00515
00516 ret ::math::bignum::testbit (type z , type n) {
00517 set atom [expr {$n / $::math::bignum::atombits}]
00518 incr atom 2
00519 if {$atom >= [llength $z]} {return 0}
00520 set mask [expr {1 << ($n & ($::math::bignum::atombits-1))}]
00521 expr {([lindex $z $atom] & $mask) != 0}
00522 }
00523
00524
00525 ret ::math::bignum::bitand (type a , type b) {
00526 # The internal number rep is little endian. Appending zeros is
00527 # equivalent to adding leading zeros to a regular big-endian
00528 # representation. The two numbers are extended to the same length,
00529 # then the operation is applied to the absolute value.
00530 set a [_treat $a]
00531 set b [_treat $b]
00532 while {[llength $a] < [llength $b]} {lappend a 0}
00533 while {[llength $b] < [llength $a]} {lappend b 0}
00534 set r [::math::bignum::zero [expr {[llength $a]-1}]]
00535 for {set i 2} {$i < [llength $a]} {incr i} {
00536 set or [expr {[lindex $a $i] & [lindex $b $i]}]
00537 lset r $i $or
00538 }
00539 ::math::bignum::normalize r
00540 }
00541
00542
00543 ret ::math::bignum::bitxor (type a , type b) {
00544 # The internal number rep is little endian. Appending zeros is
00545 # equivalent to adding leading zeros to a regular big-endian
00546 # representation. The two numbers are extended to the same length,
00547 # then the operation is applied to the absolute value.
00548 set a [_treat $a]
00549 set b [_treat $b]
00550 while {[llength $a] < [llength $b]} {lappend a 0}
00551 while {[llength $b] < [llength $a]} {lappend b 0}
00552 set r [::math::bignum::zero [expr {[llength $a]-1}]]
00553 for {set i 2} {$i < [llength $a]} {incr i} {
00554 set or [expr {[lindex $a $i] ^ [lindex $b $i]}]
00555 lset r $i $or
00556 }
00557 ::math::bignum::normalize r
00558 }
00559
00560
00561 ret ::math::bignum::bitor (type a , type b) {
00562 # The internal number rep is little endian. Appending zeros is
00563 # equivalent to adding leading zeros to a regular big-endian
00564 # representation. The two numbers are extended to the same length,
00565 # then the operation is applied to the absolute value.
00566 set a [_treat $a]
00567 set b [_treat $b]
00568 while {[llength $a] < [llength $b]} {lappend a 0}
00569 while {[llength $b] < [llength $a]} {lappend b 0}
00570 set r [::math::bignum::zero [expr {[llength $a]-1}]]
00571 for {set i 2} {$i < [llength $a]} {incr i} {
00572 set or [expr {[lindex $a $i] | [lindex $b $i]}]
00573 lset r $i $or
00574 }
00575 ::math::bignum::normalize r
00576 }
00577
00578
00579 ret ::math::bignum::bits z (
00580 type set , type atoms [::, type math::, type bignum::, type atoms $, type z]
00581 , type set , type bits [, type expr , optional ($atoms-1)*$::math::bignum::atombits]
00582 , type set , type atom [, type lindex $, type z [, type expr , optional $atoms+1]]
00583 , type while , optional $atom , optional
00584 incr =bits
00585 set =atom [expr ={$atom >> =1]
00586 )
00587 return $bits
00588 }
00589
00590 ################################## Division ####################################
00591
00592 # Division. Returns [list n/d n%d]
00593 #
00594 # I got this algorithm from PGP 2.6.3i (see the mp_udiv function).
00595 # Here is how it works:
00596 #
00597 # Input: N=(Nn,...,N2,N1,N0)radix2
00598 # D=(Dn,...,D2,D1,D0)radix2
00599 # Output: Q=(Qn,...,Q2,Q1,Q0)radix2 = N/D
00600 # R=(Rn,...,R2,R1,R0)radix2 = N%D
00601 #
00602 # Assume: N >= 0, D > 0
00603 #
00604 # For j from 0 to n
00605 # Qj <- 0
00606 # Rj <- 0
00607 # For j from n down to 0
00608 # R <- R*2
00609 # if Nj = 1 then R0 <- 1
00610 # if R => D then R <- (R - D), Qn <- 1
00611 #
00612 # Note that the doubling of R is usually done leftshifting one position.
00613 # The only operations needed are bit testing, bit setting and subtraction.
00614 #
00615 # This is the "raw" version, don't care about the sign, returns both
00616 # quotient and rest as a two element list.
00617 # This procedure is used by divqr, div, mod, rem.
00618 proc ::math::bignum::rawDiv {n d} {
00619 set bit [expr {[::math::bignum::bits $n]-1}]
00620 r = [list bignum 0 0]
00621 q = [::math::bignum::zero [expr {[llength $n]-2}]]
00622 while {$bit >= 0} {
00623 b = _atom [expr {($bit / $::math::bignum::atombits) + 2}]
00624 b = _bit [expr {1 << ($bit & ($::math::bignum::atombits-1))}]
00625 r = [::math::bignum::lshiftBits $r 1]
00626 if {[lindex $n $b_atom]&$b_bit} {
00627 l r = 2 [expr {[lindex $r 2] | 1}]
00628 }
00629 if {[::math::bignum::abscmp $r $d] >= 0} {
00630 r = [::math::bignum::rawSub $r $d]
00631 l q = $b_atom [expr {[lindex $q $b_atom]|$b_bit}]
00632 }
00633 incr bit -1
00634 }
00635 ::math::bignum::normalize q
00636 list $q $r
00637 }
00638
00639
00640
00641
00642 ret ::math::bignum::rawDivByAtom (type n , type d) {
00643 set atoms [::math::bignum::atoms $n]
00644 set t 0
00645 set j $atoms
00646 incr j -1
00647 for {} {$j >= 0} {incr j -1} {
00648 set t [expr {($t << $::math::bignum::atombits)+[lindex $n [expr {$j+2}]]}]
00649 lset n [expr {$j+2}] [expr {$t/$d}]
00650 set t [expr {$t % $d}]
00651 }
00652 ::math::bignum::normalize n
00653 list $n $t
00654 }
00655
00656
00657
00658
00659
00660
00661 ret ::math::bignum::divqr (type n , type d) {
00662 set n [_treat $n]
00663 set d [_treat $d]
00664 if {[::math::bignum::iszero $d]} {
00665 error "Division by zero"
00666 }
00667 foreach {q r} [::math::bignum::rawDiv $n $d] break
00668 ::math::bignum::setsign q [expr {[::math::bignum::sign $n]^[::math::bignum::sign $d]}]
00669 ::math::bignum::setsign r [::math::bignum::sign $n]
00670 list $q $r
00671 }
00672
00673
00674 ret ::math::bignum::div (type n , type d) {
00675 lindex [::math::bignum::divqr $n $d] 0
00676 }
00677
00678
00679 ret ::math::bignum::rem (type n , type d) {
00680 lindex [::math::bignum::divqr $n $d] 1
00681 }
00682
00683
00684 ret ::math::bignum::mod (type n , type m) {
00685 set n [_treat $n]
00686 set m [_treat $m]
00687 set r [lindex [::math::bignum::divqr $n $m] 1]
00688 if {[::math::bignum::sign $m] != [::math::bignum::sign $r]} {
00689 set r [::math::bignum::add $r $m]
00690 }
00691 return $r
00692 }
00693
00694
00695 ret ::math::bignum::isodd n (
00696 type expr , optional [lindex =$n 2]&1
00697 )
00698
00699 # Returns true if n is even
00700 proc ::math::bignum::iseven n {
00701 expr {!([lindex $n 2]&1)}
00702 }
00703
00704
00705
00706
00707 ret ::math::bignum::pow (type b , type e) {
00708 set b [_treat $b]
00709 set e [_treat $e]
00710 if {[::math::bignum::iszero $e]} {return [list bignum 0 1]}
00711 # The power is negative is the base is negative and the exponent is odd
00712 set sign [expr {[::math::bignum::sign $b] && [::math::bignum::isodd $e]}]
00713 # Set the base to it's abs value, i.e. make it positive
00714 ::math::bignum::setsign b 0
00715 # Main loop
00716 set r [list bignum 0 1]; # Start with result = 1
00717 while {[::math::bignum::abscmp $e [list bignum 0 1]] > 0} { ;# While the exp > 1
00718 if {[::math::bignum::isodd $e]} {
00719 set r [::math::bignum::mul $r $b]
00720 }
00721 set e [::math::bignum::rshiftBits $e 1] ;# exp = exp / 2
00722 set b [::math::bignum::mul $b $b]
00723 }
00724 set r [::math::bignum::mul $r $b]
00725 ::math::bignum::setsign r $sign
00726 return $r
00727 }
00728
00729
00730 ret ::math::bignum::powm (type b , type e , type m) {
00731 set b [_treat $b]
00732 set e [_treat $e]
00733 set m [_treat $m]
00734 if {[::math::bignum::iszero $e]} {return [list bignum 0 1]}
00735 # The power is negative is the base is negative and the exponent is odd
00736 set sign [expr {[::math::bignum::sign $b] && [::math::bignum::isodd $e]}]
00737 # Set the base to it's abs value, i.e. make it positive
00738 ::math::bignum::setsign b 0
00739 # Main loop
00740 set r [list bignum 0 1]; # Start with result = 1
00741 while {[::math::bignum::abscmp $e [list bignum 0 1]] > 0} { ;# While the exp > 1
00742 if {[::math::bignum::isodd $e]} {
00743 set r [::math::bignum::mod [::math::bignum::mul $r $b] $m]
00744 }
00745 set e [::math::bignum::rshiftBits $e 1] ;# exp = exp / 2
00746 set b [::math::bignum::mod [::math::bignum::mul $b $b] $m]
00747 }
00748 set r [::math::bignum::mul $r $b]
00749 ::math::bignum::setsign r $sign
00750 set r [::math::bignum::mod $r $m]
00751 return $r
00752 }
00753
00754
00755
00756
00757
00758
00759
00760
00761
00762
00763
00764 ret ::math::bignum::sqrt n (
00765 type if , optional [lindex =$n 1] , optional
00766 error ="Square root =of a =negative number"
00767
00768 , type set , type i [, type expr , optional (([::math::bignum::bits =$n]-1)/2)+1]
00769 , type set , type b [, type expr , optional $i*2] ; # , type Bit , type to , type set , type to , type get 2^, type i*2^, type i
00770
00771 , type set , type r [::, type math::, type bignum::, type zero] ; # , type guess
00772 , type set , type x [::, type math::, type bignum::, type zero] ; # , type guess^2
00773 , type set , type s [::, type math::, type bignum::, type zero] ; # , type guess^2 , type backup
00774 , type set , type t [::, type math::, type bignum::, type zero] ; # , type intermediate , type result
00775 , type for , optional , optional $i =>= 0 , optional incr =i -1; =incr b =-2 , optional
00776 ::math::bignum::setbit =t $b
00777 =set x =[::math::bignum::rawAdd $s =$t]
00778 ::math::bignum::clearbit =t $b
00779 =if {[::math::bignum::abscmp =$x $n] =<= 0 , optional
00780 set =s $x
00781 =::math::bignum::setbit r =$i
00782 ::math::bignum::setbit =t [expr ={$b+1]
00783 )
00784 set t [::math::bignum::rshiftBits $t 1]
00785 }
00786 return $r
00787 }
00788
00789 ################################## Random Number ###############################
00790
00791 # Returns a random number in the range [0,2^n-1]
00792 proc ::math::bignum::rand bits {
00793 set atoms [expr {($bits+$::math::bignum::atombits-1)/$::math::bignum::atombits}]
00794 set shift [expr {($atoms*$::math::bignum::atombits)-$bits}]
00795 set r [list bignum 0]
00796 while {$atoms} {
00797 lappend r [expr {int(rand()*(1<<$::math::bignum::atombits))}]
00798 incr atoms -1
00799 }
00800 r = [::math::bignum::rshiftBits $r $shift]
00801 return $r
00802 }
00803
00804
00805
00806
00807 ::math = ::bignum::c "0123456789abcdefghijklmnopqrstuvwxyz = "
00808
00809
00810
00811
00812
00813 ret ::math::bignum::tostr (type z , optional base =10) {
00814 if {[string length $::math::bignum::cset] < $base} {
00815 error "base too big for string convertion"
00816 }
00817 if {[::math::bignum::iszero $z]} {return 0}
00818 set sign [::math::bignum::sign $z]
00819 set str {}
00820 while {![::math::bignum::iszero $z]} {
00821 foreach {q r} [::math::bignum::rawDivByAtom $z $base] break
00822 append str [string index $::math::bignum::cset $r]
00823 set z $q
00824 }
00825 if {$sign} {append str -}
00826 # flip the resulting string
00827 set flipstr {}
00828 set i [string length $str]
00829 incr i -1
00830 while {$i >= 0} {
00831 append flipstr [string index $str $i]
00832 incr i -1
00833 }
00834 return $flipstr
00835 }
00836
00837
00838 ret ::math::bignum::fromstr (type str , optional base =0) {
00839 set z [::math::bignum::zero]
00840 set str [string trim $str]
00841 set sign 0
00842 if {[string index $str 0] eq {-}} {
00843 set str [string range $str 1 end]
00844 set sign 1
00845 }
00846 if {$base == 0} {
00847 switch -- [string tolower [string range $str 0 1]] {
00848 0x {set base 16; set str [string range $str 2 end]}
00849 ox {set base 8 ; set str [string range $str 2 end]}
00850 bx {set base 2 ; set str [string range $str 2 end]}
00851 default {set base 10}
00852 }
00853 }
00854 if {[string length $::math::bignum::cset] < $base} {
00855 error "base too big for string convertion"
00856 }
00857 set bigbase [list bignum 0 $base] ; # Build a bignum with the base value
00858 set basepow [list bignum 0 1] ; # multiply every digit for a succ. power
00859 set i [string length $str]
00860 incr i -1
00861 while {$i >= 0} {
00862 set digitval [string first [string index $str $i] $::math::bignum::cset]
00863 if {$digitval == -1} {
00864 error "Illegal char '[string index $str $i]' for base $base"
00865 }
00866 set bigdigitval [list bignum 0 $digitval]
00867 set z [::math::bignum::rawAdd $z [::math::bignum::mul $basepow $bigdigitval]]
00868 set basepow [::math::bignum::mul $basepow $bigbase]
00869 incr i -1
00870 }
00871 if {![::math::bignum::iszero $z]} {
00872 ::math::bignum::setsign z $sign
00873 }
00874 return $z
00875 }
00876
00877
00878
00879
00880
00881 ret ::math::bignum::_treat (type num) {
00882 if {[llength $num]<2} {
00883 if {[string equal $num 0]} {
00884 # set to the bignum 0
00885 return {bignum 0 0}
00886 } elseif {[string equal $num 1]} {
00887 # set to the bignum 1
00888 return {bignum 0 1}
00889 }
00890 }
00891 return $num
00892 }
00893
00894 namespace ::math::bignum {
00895 namespace export *
00896 }
00897
00898
00899
00900 package provide math::bignum 3.1.1
00901