1 | package Math::BigInt::Calc;
|
---|
2 |
|
---|
3 | use 5.005;
|
---|
4 | use strict;
|
---|
5 | # use warnings; # dont use warnings for older Perls
|
---|
6 |
|
---|
7 | use vars qw/$VERSION/;
|
---|
8 |
|
---|
9 | $VERSION = '0.47';
|
---|
10 |
|
---|
11 | # Package to store unsigned big integers in decimal and do math with them
|
---|
12 |
|
---|
13 | # Internally the numbers are stored in an array with at least 1 element, no
|
---|
14 | # leading zero parts (except the first) and in base 1eX where X is determined
|
---|
15 | # automatically at loading time to be the maximum possible value
|
---|
16 |
|
---|
17 | # todo:
|
---|
18 | # - fully remove funky $# stuff in div() (maybe - that code scares me...)
|
---|
19 |
|
---|
20 | # USE_MUL: due to problems on certain os (os390, posix-bc) "* 1e-5" is used
|
---|
21 | # instead of "/ 1e5" at some places, (marked with USE_MUL). Other platforms
|
---|
22 | # BS2000, some Crays need USE_DIV instead.
|
---|
23 | # The BEGIN block is used to determine which of the two variants gives the
|
---|
24 | # correct result.
|
---|
25 |
|
---|
26 | # Beware of things like:
|
---|
27 | # $i = $i * $y + $car; $car = int($i / $MBASE); $i = $i % $MBASE;
|
---|
28 | # This works on x86, but fails on ARM (SA1100, iPAQ) due to whoknows what
|
---|
29 | # reasons. So, use this instead (slower, but correct):
|
---|
30 | # $i = $i * $y + $car; $car = int($i / $MBASE); $i -= $MBASE * $car;
|
---|
31 |
|
---|
32 | ##############################################################################
|
---|
33 | # global constants, flags and accessory
|
---|
34 |
|
---|
35 | # announce that we are compatible with MBI v1.70 and up
|
---|
36 | sub api_version () { 1; }
|
---|
37 |
|
---|
38 | # constants for easier life
|
---|
39 | my ($BASE,$BASE_LEN,$MBASE,$RBASE,$MAX_VAL,$BASE_LEN_SMALL);
|
---|
40 | my ($AND_BITS,$XOR_BITS,$OR_BITS);
|
---|
41 | my ($AND_MASK,$XOR_MASK,$OR_MASK);
|
---|
42 |
|
---|
43 | sub _base_len
|
---|
44 | {
|
---|
45 | # set/get the BASE_LEN and assorted other, connected values
|
---|
46 | # used only be the testsuite, set is used only by the BEGIN block below
|
---|
47 | shift;
|
---|
48 |
|
---|
49 | my $b = shift;
|
---|
50 | if (defined $b)
|
---|
51 | {
|
---|
52 | # find whether we can use mul or div or none in mul()/div()
|
---|
53 | # (in last case reduce BASE_LEN_SMALL)
|
---|
54 | $BASE_LEN_SMALL = $b+1;
|
---|
55 | my $caught = 0;
|
---|
56 | while (--$BASE_LEN_SMALL > 5)
|
---|
57 | {
|
---|
58 | $MBASE = int("1e".$BASE_LEN_SMALL);
|
---|
59 | $RBASE = abs('1e-'.$BASE_LEN_SMALL); # see USE_MUL
|
---|
60 | $caught = 0;
|
---|
61 | $caught += 1 if (int($MBASE * $RBASE) != 1); # should be 1
|
---|
62 | $caught += 2 if (int($MBASE / $MBASE) != 1); # should be 1
|
---|
63 | last if $caught != 3;
|
---|
64 | }
|
---|
65 | # BASE_LEN is used for anything else than mul()/div()
|
---|
66 | $BASE_LEN = $BASE_LEN_SMALL;
|
---|
67 | $BASE_LEN = shift if (defined $_[0]); # one more arg?
|
---|
68 | $BASE = int("1e".$BASE_LEN);
|
---|
69 |
|
---|
70 | $MBASE = int("1e".$BASE_LEN_SMALL);
|
---|
71 | $RBASE = abs('1e-'.$BASE_LEN_SMALL); # see USE_MUL
|
---|
72 | $MAX_VAL = $MBASE-1;
|
---|
73 |
|
---|
74 | # avoid redefinitions
|
---|
75 |
|
---|
76 | undef &_mul;
|
---|
77 | undef &_div;
|
---|
78 |
|
---|
79 | # $caught & 1 != 0 => cannot use MUL
|
---|
80 | # $caught & 2 != 0 => cannot use DIV
|
---|
81 | # The parens around ($caught & 1) were important, indeed, if we would use
|
---|
82 | # & here.
|
---|
83 | if ($caught == 2) # 2
|
---|
84 | {
|
---|
85 | # must USE_MUL since we cannot use DIV
|
---|
86 | *{_mul} = \&_mul_use_mul;
|
---|
87 | *{_div} = \&_div_use_mul;
|
---|
88 | }
|
---|
89 | else # 0 or 1
|
---|
90 | {
|
---|
91 | # can USE_DIV instead
|
---|
92 | *{_mul} = \&_mul_use_div;
|
---|
93 | *{_div} = \&_div_use_div;
|
---|
94 | }
|
---|
95 | }
|
---|
96 | return $BASE_LEN unless wantarray;
|
---|
97 | return ($BASE_LEN, $AND_BITS, $XOR_BITS, $OR_BITS, $BASE_LEN_SMALL, $MAX_VAL, $BASE);
|
---|
98 | }
|
---|
99 |
|
---|
100 | sub _new
|
---|
101 | {
|
---|
102 | # (ref to string) return ref to num_array
|
---|
103 | # Convert a number from string format (without sign) to internal base
|
---|
104 | # 1ex format. Assumes normalized value as input.
|
---|
105 | my $il = length($_[1])-1;
|
---|
106 |
|
---|
107 | # < BASE_LEN due len-1 above
|
---|
108 | return [ int($_[1]) ] if $il < $BASE_LEN; # shortcut for short numbers
|
---|
109 |
|
---|
110 | # this leaves '00000' instead of int 0 and will be corrected after any op
|
---|
111 | [ reverse(unpack("a" . ($il % $BASE_LEN+1)
|
---|
112 | . ("a$BASE_LEN" x ($il / $BASE_LEN)), $_[1])) ];
|
---|
113 | }
|
---|
114 |
|
---|
115 | BEGIN
|
---|
116 | {
|
---|
117 | # from Daniel Pfeiffer: determine largest group of digits that is precisely
|
---|
118 | # multipliable with itself plus carry
|
---|
119 | # Test now changed to expect the proper pattern, not a result off by 1 or 2
|
---|
120 | my ($e, $num) = 3; # lowest value we will use is 3+1-1 = 3
|
---|
121 | do
|
---|
122 | {
|
---|
123 | $num = ('9' x ++$e) + 0;
|
---|
124 | $num *= $num + 1.0;
|
---|
125 | } while ("$num" =~ /9{$e}0{$e}/); # must be a certain pattern
|
---|
126 | $e--; # last test failed, so retract one step
|
---|
127 | # the limits below brush the problems with the test above under the rug:
|
---|
128 | # the test should be able to find the proper $e automatically
|
---|
129 | $e = 5 if $^O =~ /^uts/; # UTS get's some special treatment
|
---|
130 | $e = 5 if $^O =~ /^unicos/; # unicos is also problematic (6 seems to work
|
---|
131 | # there, but we play safe)
|
---|
132 | $e = 5 if $] < 5.006; # cap, for older Perls
|
---|
133 | $e = 7 if $e > 7; # cap, for VMS, OS/390 and other 64 bit systems
|
---|
134 | # 8 fails inside random testsuite, so take 7
|
---|
135 |
|
---|
136 | __PACKAGE__->_base_len($e); # set and store
|
---|
137 |
|
---|
138 | use integer;
|
---|
139 | # find out how many bits _and, _or and _xor can take (old default = 16)
|
---|
140 | # I don't think anybody has yet 128 bit scalars, so let's play safe.
|
---|
141 | local $^W = 0; # don't warn about 'nonportable number'
|
---|
142 | $AND_BITS = 15; $XOR_BITS = 15; $OR_BITS = 15;
|
---|
143 |
|
---|
144 | # find max bits, we will not go higher than numberofbits that fit into $BASE
|
---|
145 | # to make _and etc simpler (and faster for smaller, slower for large numbers)
|
---|
146 | my $max = 16;
|
---|
147 | while (2 ** $max < $BASE) { $max++; }
|
---|
148 | {
|
---|
149 | no integer;
|
---|
150 | $max = 16 if $] < 5.006; # older Perls might not take >16 too well
|
---|
151 | }
|
---|
152 | my ($x,$y,$z);
|
---|
153 | do {
|
---|
154 | $AND_BITS++;
|
---|
155 | $x = oct('0b' . '1' x $AND_BITS); $y = $x & $x;
|
---|
156 | $z = (2 ** $AND_BITS) - 1;
|
---|
157 | } while ($AND_BITS < $max && $x == $z && $y == $x);
|
---|
158 | $AND_BITS --; # retreat one step
|
---|
159 | do {
|
---|
160 | $XOR_BITS++;
|
---|
161 | $x = oct('0b' . '1' x $XOR_BITS); $y = $x ^ 0;
|
---|
162 | $z = (2 ** $XOR_BITS) - 1;
|
---|
163 | } while ($XOR_BITS < $max && $x == $z && $y == $x);
|
---|
164 | $XOR_BITS --; # retreat one step
|
---|
165 | do {
|
---|
166 | $OR_BITS++;
|
---|
167 | $x = oct('0b' . '1' x $OR_BITS); $y = $x | $x;
|
---|
168 | $z = (2 ** $OR_BITS) - 1;
|
---|
169 | } while ($OR_BITS < $max && $x == $z && $y == $x);
|
---|
170 | $OR_BITS --; # retreat one step
|
---|
171 |
|
---|
172 | $AND_MASK = __PACKAGE__->_new( ( 2 ** $AND_BITS ));
|
---|
173 | $XOR_MASK = __PACKAGE__->_new( ( 2 ** $XOR_BITS ));
|
---|
174 | $OR_MASK = __PACKAGE__->_new( ( 2 ** $OR_BITS ));
|
---|
175 | }
|
---|
176 |
|
---|
177 | ###############################################################################
|
---|
178 |
|
---|
179 | sub _zero
|
---|
180 | {
|
---|
181 | # create a zero
|
---|
182 | [ 0 ];
|
---|
183 | }
|
---|
184 |
|
---|
185 | sub _one
|
---|
186 | {
|
---|
187 | # create a one
|
---|
188 | [ 1 ];
|
---|
189 | }
|
---|
190 |
|
---|
191 | sub _two
|
---|
192 | {
|
---|
193 | # create a two (used internally for shifting)
|
---|
194 | [ 2 ];
|
---|
195 | }
|
---|
196 |
|
---|
197 | sub _ten
|
---|
198 | {
|
---|
199 | # create a 10 (used internally for shifting)
|
---|
200 | [ 10 ];
|
---|
201 | }
|
---|
202 |
|
---|
203 | sub _copy
|
---|
204 | {
|
---|
205 | # make a true copy
|
---|
206 | [ @{$_[1]} ];
|
---|
207 | }
|
---|
208 |
|
---|
209 | # catch and throw away
|
---|
210 | sub import { }
|
---|
211 |
|
---|
212 | ##############################################################################
|
---|
213 | # convert back to string and number
|
---|
214 |
|
---|
215 | sub _str
|
---|
216 | {
|
---|
217 | # (ref to BINT) return num_str
|
---|
218 | # Convert number from internal base 100000 format to string format.
|
---|
219 | # internal format is always normalized (no leading zeros, "-0" => "+0")
|
---|
220 | my $ar = $_[1];
|
---|
221 |
|
---|
222 | my $l = scalar @$ar; # number of parts
|
---|
223 | if ($l < 1) # should not happen
|
---|
224 | {
|
---|
225 | require Carp;
|
---|
226 | Carp::croak("$_[1] has no elements");
|
---|
227 | }
|
---|
228 |
|
---|
229 | my $ret = "";
|
---|
230 | # handle first one different to strip leading zeros from it (there are no
|
---|
231 | # leading zero parts in internal representation)
|
---|
232 | $l --; $ret .= int($ar->[$l]); $l--;
|
---|
233 | # Interestingly, the pre-padd method uses more time
|
---|
234 | # the old grep variant takes longer (14 vs. 10 sec)
|
---|
235 | my $z = '0' x ($BASE_LEN-1);
|
---|
236 | while ($l >= 0)
|
---|
237 | {
|
---|
238 | $ret .= substr($z.$ar->[$l],-$BASE_LEN); # fastest way I could think of
|
---|
239 | $l--;
|
---|
240 | }
|
---|
241 | $ret;
|
---|
242 | }
|
---|
243 |
|
---|
244 | sub _num
|
---|
245 | {
|
---|
246 | # Make a number (scalar int/float) from a BigInt object
|
---|
247 | my $x = $_[1];
|
---|
248 |
|
---|
249 | return 0+$x->[0] if scalar @$x == 1; # below $BASE
|
---|
250 | my $fac = 1;
|
---|
251 | my $num = 0;
|
---|
252 | foreach (@$x)
|
---|
253 | {
|
---|
254 | $num += $fac*$_; $fac *= $BASE;
|
---|
255 | }
|
---|
256 | $num;
|
---|
257 | }
|
---|
258 |
|
---|
259 | ##############################################################################
|
---|
260 | # actual math code
|
---|
261 |
|
---|
262 | sub _add
|
---|
263 | {
|
---|
264 | # (ref to int_num_array, ref to int_num_array)
|
---|
265 | # routine to add two base 1eX numbers
|
---|
266 | # stolen from Knuth Vol 2 Algorithm A pg 231
|
---|
267 | # there are separate routines to add and sub as per Knuth pg 233
|
---|
268 | # This routine clobbers up array x, but not y.
|
---|
269 |
|
---|
270 | my ($c,$x,$y) = @_;
|
---|
271 |
|
---|
272 | return $x if (@$y == 1) && $y->[0] == 0; # $x + 0 => $x
|
---|
273 | if ((@$x == 1) && $x->[0] == 0) # 0 + $y => $y->copy
|
---|
274 | {
|
---|
275 | # twice as slow as $x = [ @$y ], but necc. to retain $x as ref :(
|
---|
276 | @$x = @$y; return $x;
|
---|
277 | }
|
---|
278 |
|
---|
279 | # for each in Y, add Y to X and carry. If after that, something is left in
|
---|
280 | # X, foreach in X add carry to X and then return X, carry
|
---|
281 | # Trades one "$j++" for having to shift arrays
|
---|
282 | my $i; my $car = 0; my $j = 0;
|
---|
283 | for $i (@$y)
|
---|
284 | {
|
---|
285 | $x->[$j] -= $BASE if $car = (($x->[$j] += $i + $car) >= $BASE) ? 1 : 0;
|
---|
286 | $j++;
|
---|
287 | }
|
---|
288 | while ($car != 0)
|
---|
289 | {
|
---|
290 | $x->[$j] -= $BASE if $car = (($x->[$j] += $car) >= $BASE) ? 1 : 0; $j++;
|
---|
291 | }
|
---|
292 | $x;
|
---|
293 | }
|
---|
294 |
|
---|
295 | sub _inc
|
---|
296 | {
|
---|
297 | # (ref to int_num_array, ref to int_num_array)
|
---|
298 | # Add 1 to $x, modify $x in place
|
---|
299 | my ($c,$x) = @_;
|
---|
300 |
|
---|
301 | for my $i (@$x)
|
---|
302 | {
|
---|
303 | return $x if (($i += 1) < $BASE); # early out
|
---|
304 | $i = 0; # overflow, next
|
---|
305 | }
|
---|
306 | push @$x,1 if (($x->[-1] || 0) == 0); # last overflowed, so extend
|
---|
307 | $x;
|
---|
308 | }
|
---|
309 |
|
---|
310 | sub _dec
|
---|
311 | {
|
---|
312 | # (ref to int_num_array, ref to int_num_array)
|
---|
313 | # Sub 1 from $x, modify $x in place
|
---|
314 | my ($c,$x) = @_;
|
---|
315 |
|
---|
316 | my $MAX = $BASE-1; # since MAX_VAL based on MBASE
|
---|
317 | for my $i (@$x)
|
---|
318 | {
|
---|
319 | last if (($i -= 1) >= 0); # early out
|
---|
320 | $i = $MAX; # underflow, next
|
---|
321 | }
|
---|
322 | pop @$x if $x->[-1] == 0 && @$x > 1; # last underflowed (but leave 0)
|
---|
323 | $x;
|
---|
324 | }
|
---|
325 |
|
---|
326 | sub _sub
|
---|
327 | {
|
---|
328 | # (ref to int_num_array, ref to int_num_array, swap)
|
---|
329 | # subtract base 1eX numbers -- stolen from Knuth Vol 2 pg 232, $x > $y
|
---|
330 | # subtract Y from X by modifying x in place
|
---|
331 | my ($c,$sx,$sy,$s) = @_;
|
---|
332 |
|
---|
333 | my $car = 0; my $i; my $j = 0;
|
---|
334 | if (!$s)
|
---|
335 | {
|
---|
336 | for $i (@$sx)
|
---|
337 | {
|
---|
338 | last unless defined $sy->[$j] || $car;
|
---|
339 | $i += $BASE if $car = (($i -= ($sy->[$j] || 0) + $car) < 0); $j++;
|
---|
340 | }
|
---|
341 | # might leave leading zeros, so fix that
|
---|
342 | return __strip_zeros($sx);
|
---|
343 | }
|
---|
344 | for $i (@$sx)
|
---|
345 | {
|
---|
346 | # we can't do an early out if $x is < than $y, since we
|
---|
347 | # need to copy the high chunks from $y. Found by Bob Mathews.
|
---|
348 | #last unless defined $sy->[$j] || $car;
|
---|
349 | $sy->[$j] += $BASE
|
---|
350 | if $car = (($sy->[$j] = $i-($sy->[$j]||0) - $car) < 0);
|
---|
351 | $j++;
|
---|
352 | }
|
---|
353 | # might leave leading zeros, so fix that
|
---|
354 | __strip_zeros($sy);
|
---|
355 | }
|
---|
356 |
|
---|
357 | sub _mul_use_mul
|
---|
358 | {
|
---|
359 | # (ref to int_num_array, ref to int_num_array)
|
---|
360 | # multiply two numbers in internal representation
|
---|
361 | # modifies first arg, second need not be different from first
|
---|
362 | my ($c,$xv,$yv) = @_;
|
---|
363 |
|
---|
364 | if (@$yv == 1)
|
---|
365 | {
|
---|
366 | # shortcut for two very short numbers (improved by Nathan Zook)
|
---|
367 | # works also if xv and yv are the same reference, and handles also $x == 0
|
---|
368 | if (@$xv == 1)
|
---|
369 | {
|
---|
370 | if (($xv->[0] *= $yv->[0]) >= $MBASE)
|
---|
371 | {
|
---|
372 | $xv->[0] = $xv->[0] - ($xv->[1] = int($xv->[0] * $RBASE)) * $MBASE;
|
---|
373 | };
|
---|
374 | return $xv;
|
---|
375 | }
|
---|
376 | # $x * 0 => 0
|
---|
377 | if ($yv->[0] == 0)
|
---|
378 | {
|
---|
379 | @$xv = (0);
|
---|
380 | return $xv;
|
---|
381 | }
|
---|
382 | # multiply a large number a by a single element one, so speed up
|
---|
383 | my $y = $yv->[0]; my $car = 0;
|
---|
384 | foreach my $i (@$xv)
|
---|
385 | {
|
---|
386 | $i = $i * $y + $car; $car = int($i * $RBASE); $i -= $car * $MBASE;
|
---|
387 | }
|
---|
388 | push @$xv, $car if $car != 0;
|
---|
389 | return $xv;
|
---|
390 | }
|
---|
391 | # shortcut for result $x == 0 => result = 0
|
---|
392 | return $xv if ( ((@$xv == 1) && ($xv->[0] == 0)) );
|
---|
393 |
|
---|
394 | # since multiplying $x with $x fails, make copy in this case
|
---|
395 | $yv = [@$xv] if $xv == $yv; # same references?
|
---|
396 |
|
---|
397 | my @prod = (); my ($prod,$car,$cty,$xi,$yi);
|
---|
398 |
|
---|
399 | for $xi (@$xv)
|
---|
400 | {
|
---|
401 | $car = 0; $cty = 0;
|
---|
402 |
|
---|
403 | # slow variant
|
---|
404 | # for $yi (@$yv)
|
---|
405 | # {
|
---|
406 | # $prod = $xi * $yi + ($prod[$cty] || 0) + $car;
|
---|
407 | # $prod[$cty++] =
|
---|
408 | # $prod - ($car = int($prod * RBASE)) * $MBASE; # see USE_MUL
|
---|
409 | # }
|
---|
410 | # $prod[$cty] += $car if $car; # need really to check for 0?
|
---|
411 | # $xi = shift @prod;
|
---|
412 |
|
---|
413 | # faster variant
|
---|
414 | # looping through this if $xi == 0 is silly - so optimize it away!
|
---|
415 | $xi = (shift @prod || 0), next if $xi == 0;
|
---|
416 | for $yi (@$yv)
|
---|
417 | {
|
---|
418 | $prod = $xi * $yi + ($prod[$cty] || 0) + $car;
|
---|
419 | ## this is actually a tad slower
|
---|
420 | ## $prod = $prod[$cty]; $prod += ($car + $xi * $yi); # no ||0 here
|
---|
421 | $prod[$cty++] =
|
---|
422 | $prod - ($car = int($prod * $RBASE)) * $MBASE; # see USE_MUL
|
---|
423 | }
|
---|
424 | $prod[$cty] += $car if $car; # need really to check for 0?
|
---|
425 | $xi = shift @prod || 0; # || 0 makes v5.005_3 happy
|
---|
426 | }
|
---|
427 | push @$xv, @prod;
|
---|
428 | __strip_zeros($xv);
|
---|
429 | $xv;
|
---|
430 | }
|
---|
431 |
|
---|
432 | sub _mul_use_div
|
---|
433 | {
|
---|
434 | # (ref to int_num_array, ref to int_num_array)
|
---|
435 | # multiply two numbers in internal representation
|
---|
436 | # modifies first arg, second need not be different from first
|
---|
437 | my ($c,$xv,$yv) = @_;
|
---|
438 |
|
---|
439 | if (@$yv == 1)
|
---|
440 | {
|
---|
441 | # shortcut for two small numbers, also handles $x == 0
|
---|
442 | if (@$xv == 1)
|
---|
443 | {
|
---|
444 | # shortcut for two very short numbers (improved by Nathan Zook)
|
---|
445 | # works also if xv and yv are the same reference, and handles also $x == 0
|
---|
446 | if (($xv->[0] *= $yv->[0]) >= $MBASE)
|
---|
447 | {
|
---|
448 | $xv->[0] =
|
---|
449 | $xv->[0] - ($xv->[1] = int($xv->[0] / $MBASE)) * $MBASE;
|
---|
450 | };
|
---|
451 | return $xv;
|
---|
452 | }
|
---|
453 | # $x * 0 => 0
|
---|
454 | if ($yv->[0] == 0)
|
---|
455 | {
|
---|
456 | @$xv = (0);
|
---|
457 | return $xv;
|
---|
458 | }
|
---|
459 | # multiply a large number a by a single element one, so speed up
|
---|
460 | my $y = $yv->[0]; my $car = 0;
|
---|
461 | foreach my $i (@$xv)
|
---|
462 | {
|
---|
463 | $i = $i * $y + $car; $car = int($i / $MBASE); $i -= $car * $MBASE;
|
---|
464 | }
|
---|
465 | push @$xv, $car if $car != 0;
|
---|
466 | return $xv;
|
---|
467 | }
|
---|
468 | # shortcut for result $x == 0 => result = 0
|
---|
469 | return $xv if ( ((@$xv == 1) && ($xv->[0] == 0)) );
|
---|
470 |
|
---|
471 | # since multiplying $x with $x fails, make copy in this case
|
---|
472 | $yv = [@$xv] if $xv == $yv; # same references?
|
---|
473 |
|
---|
474 | my @prod = (); my ($prod,$car,$cty,$xi,$yi);
|
---|
475 | for $xi (@$xv)
|
---|
476 | {
|
---|
477 | $car = 0; $cty = 0;
|
---|
478 | # looping through this if $xi == 0 is silly - so optimize it away!
|
---|
479 | $xi = (shift @prod || 0), next if $xi == 0;
|
---|
480 | for $yi (@$yv)
|
---|
481 | {
|
---|
482 | $prod = $xi * $yi + ($prod[$cty] || 0) + $car;
|
---|
483 | $prod[$cty++] =
|
---|
484 | $prod - ($car = int($prod / $MBASE)) * $MBASE;
|
---|
485 | }
|
---|
486 | $prod[$cty] += $car if $car; # need really to check for 0?
|
---|
487 | $xi = shift @prod || 0; # || 0 makes v5.005_3 happy
|
---|
488 | }
|
---|
489 | push @$xv, @prod;
|
---|
490 | __strip_zeros($xv);
|
---|
491 | $xv;
|
---|
492 | }
|
---|
493 |
|
---|
494 | sub _div_use_mul
|
---|
495 | {
|
---|
496 | # ref to array, ref to array, modify first array and return remainder if
|
---|
497 | # in list context
|
---|
498 |
|
---|
499 | # see comments in _div_use_div() for more explanations
|
---|
500 |
|
---|
501 | my ($c,$x,$yorg) = @_;
|
---|
502 |
|
---|
503 | # the general div algorithmn here is about O(N*N) and thus quite slow, so
|
---|
504 | # we first check for some special cases and use shortcuts to handle them.
|
---|
505 |
|
---|
506 | # This works, because we store the numbers in a chunked format where each
|
---|
507 | # element contains 5..7 digits (depending on system).
|
---|
508 |
|
---|
509 | # if both numbers have only one element:
|
---|
510 | if (@$x == 1 && @$yorg == 1)
|
---|
511 | {
|
---|
512 | # shortcut, $yorg and $x are two small numbers
|
---|
513 | if (wantarray)
|
---|
514 | {
|
---|
515 | my $r = [ $x->[0] % $yorg->[0] ];
|
---|
516 | $x->[0] = int($x->[0] / $yorg->[0]);
|
---|
517 | return ($x,$r);
|
---|
518 | }
|
---|
519 | else
|
---|
520 | {
|
---|
521 | $x->[0] = int($x->[0] / $yorg->[0]);
|
---|
522 | return $x;
|
---|
523 | }
|
---|
524 | }
|
---|
525 |
|
---|
526 | # if x has more than one, but y has only one element:
|
---|
527 | if (@$yorg == 1)
|
---|
528 | {
|
---|
529 | my $rem;
|
---|
530 | $rem = _mod($c,[ @$x ],$yorg) if wantarray;
|
---|
531 |
|
---|
532 | # shortcut, $y is < $BASE
|
---|
533 | my $j = scalar @$x; my $r = 0;
|
---|
534 | my $y = $yorg->[0]; my $b;
|
---|
535 | while ($j-- > 0)
|
---|
536 | {
|
---|
537 | $b = $r * $MBASE + $x->[$j];
|
---|
538 | $x->[$j] = int($b/$y);
|
---|
539 | $r = $b % $y;
|
---|
540 | }
|
---|
541 | pop @$x if @$x > 1 && $x->[-1] == 0; # splice up a leading zero
|
---|
542 | return ($x,$rem) if wantarray;
|
---|
543 | return $x;
|
---|
544 | }
|
---|
545 |
|
---|
546 | # now x and y have more than one element
|
---|
547 |
|
---|
548 | # check whether y has more elements than x, if yet, the result will be 0
|
---|
549 | if (@$yorg > @$x)
|
---|
550 | {
|
---|
551 | my $rem;
|
---|
552 | $rem = [@$x] if wantarray; # make copy
|
---|
553 | splice (@$x,1); # keep ref to original array
|
---|
554 | $x->[0] = 0; # set to 0
|
---|
555 | return ($x,$rem) if wantarray; # including remainder?
|
---|
556 | return $x; # only x, which is [0] now
|
---|
557 | }
|
---|
558 | # check whether the numbers have the same number of elements, in that case
|
---|
559 | # the result will fit into one element and can be computed efficiently
|
---|
560 | if (@$yorg == @$x)
|
---|
561 | {
|
---|
562 | my $rem;
|
---|
563 | # if $yorg has more digits than $x (it's leading element is longer than
|
---|
564 | # the one from $x), the result will also be 0:
|
---|
565 | if (length(int($yorg->[-1])) > length(int($x->[-1])))
|
---|
566 | {
|
---|
567 | $rem = [@$x] if wantarray; # make copy
|
---|
568 | splice (@$x,1); # keep ref to org array
|
---|
569 | $x->[0] = 0; # set to 0
|
---|
570 | return ($x,$rem) if wantarray; # including remainder?
|
---|
571 | return $x;
|
---|
572 | }
|
---|
573 | # now calculate $x / $yorg
|
---|
574 | if (length(int($yorg->[-1])) == length(int($x->[-1])))
|
---|
575 | {
|
---|
576 | # same length, so make full compare
|
---|
577 |
|
---|
578 | my $a = 0; my $j = scalar @$x - 1;
|
---|
579 | # manual way (abort if unequal, good for early ne)
|
---|
580 | while ($j >= 0)
|
---|
581 | {
|
---|
582 | last if ($a = $x->[$j] - $yorg->[$j]); $j--;
|
---|
583 | }
|
---|
584 | # $a contains the result of the compare between X and Y
|
---|
585 | # a < 0: x < y, a == 0: x == y, a > 0: x > y
|
---|
586 | if ($a <= 0)
|
---|
587 | {
|
---|
588 | $rem = [ 0 ]; # a = 0 => x == y => rem 0
|
---|
589 | $rem = [@$x] if $a != 0; # a < 0 => x < y => rem = x
|
---|
590 | splice(@$x,1); # keep single element
|
---|
591 | $x->[0] = 0; # if $a < 0
|
---|
592 | $x->[0] = 1 if $a == 0; # $x == $y
|
---|
593 | return ($x,$rem) if wantarray;
|
---|
594 | return $x;
|
---|
595 | }
|
---|
596 | # $x >= $y, so proceed normally
|
---|
597 | }
|
---|
598 | }
|
---|
599 |
|
---|
600 | # all other cases:
|
---|
601 |
|
---|
602 | my $y = [ @$yorg ]; # always make copy to preserve
|
---|
603 |
|
---|
604 | my ($car,$bar,$prd,$dd,$xi,$yi,@q,$v2,$v1,@d,$tmp,$q,$u2,$u1,$u0);
|
---|
605 |
|
---|
606 | $car = $bar = $prd = 0;
|
---|
607 | if (($dd = int($MBASE/($y->[-1]+1))) != 1)
|
---|
608 | {
|
---|
609 | for $xi (@$x)
|
---|
610 | {
|
---|
611 | $xi = $xi * $dd + $car;
|
---|
612 | $xi -= ($car = int($xi * $RBASE)) * $MBASE; # see USE_MUL
|
---|
613 | }
|
---|
614 | push(@$x, $car); $car = 0;
|
---|
615 | for $yi (@$y)
|
---|
616 | {
|
---|
617 | $yi = $yi * $dd + $car;
|
---|
618 | $yi -= ($car = int($yi * $RBASE)) * $MBASE; # see USE_MUL
|
---|
619 | }
|
---|
620 | }
|
---|
621 | else
|
---|
622 | {
|
---|
623 | push(@$x, 0);
|
---|
624 | }
|
---|
625 | @q = (); ($v2,$v1) = @$y[-2,-1];
|
---|
626 | $v2 = 0 unless $v2;
|
---|
627 | while ($#$x > $#$y)
|
---|
628 | {
|
---|
629 | ($u2,$u1,$u0) = @$x[-3..-1];
|
---|
630 | $u2 = 0 unless $u2;
|
---|
631 | #warn "oups v1 is 0, u0: $u0 $y->[-2] $y->[-1] l ",scalar @$y,"\n"
|
---|
632 | # if $v1 == 0;
|
---|
633 | $q = (($u0 == $v1) ? $MAX_VAL : int(($u0*$MBASE+$u1)/$v1));
|
---|
634 | --$q while ($v2*$q > ($u0*$MBASE+$u1-$q*$v1)*$MBASE+$u2);
|
---|
635 | if ($q)
|
---|
636 | {
|
---|
637 | ($car, $bar) = (0,0);
|
---|
638 | for ($yi = 0, $xi = $#$x-$#$y-1; $yi <= $#$y; ++$yi,++$xi)
|
---|
639 | {
|
---|
640 | $prd = $q * $y->[$yi] + $car;
|
---|
641 | $prd -= ($car = int($prd * $RBASE)) * $MBASE; # see USE_MUL
|
---|
642 | $x->[$xi] += $MBASE if ($bar = (($x->[$xi] -= $prd + $bar) < 0));
|
---|
643 | }
|
---|
644 | if ($x->[-1] < $car + $bar)
|
---|
645 | {
|
---|
646 | $car = 0; --$q;
|
---|
647 | for ($yi = 0, $xi = $#$x-$#$y-1; $yi <= $#$y; ++$yi,++$xi)
|
---|
648 | {
|
---|
649 | $x->[$xi] -= $MBASE
|
---|
650 | if ($car = (($x->[$xi] += $y->[$yi] + $car) >= $MBASE));
|
---|
651 | }
|
---|
652 | }
|
---|
653 | }
|
---|
654 | pop(@$x);
|
---|
655 | unshift(@q, $q);
|
---|
656 | }
|
---|
657 | if (wantarray)
|
---|
658 | {
|
---|
659 | @d = ();
|
---|
660 | if ($dd != 1)
|
---|
661 | {
|
---|
662 | $car = 0;
|
---|
663 | for $xi (reverse @$x)
|
---|
664 | {
|
---|
665 | $prd = $car * $MBASE + $xi;
|
---|
666 | $car = $prd - ($tmp = int($prd / $dd)) * $dd; # see USE_MUL
|
---|
667 | unshift(@d, $tmp);
|
---|
668 | }
|
---|
669 | }
|
---|
670 | else
|
---|
671 | {
|
---|
672 | @d = @$x;
|
---|
673 | }
|
---|
674 | @$x = @q;
|
---|
675 | my $d = \@d;
|
---|
676 | __strip_zeros($x);
|
---|
677 | __strip_zeros($d);
|
---|
678 | return ($x,$d);
|
---|
679 | }
|
---|
680 | @$x = @q;
|
---|
681 | __strip_zeros($x);
|
---|
682 | $x;
|
---|
683 | }
|
---|
684 |
|
---|
685 | sub _div_use_div
|
---|
686 | {
|
---|
687 | # ref to array, ref to array, modify first array and return remainder if
|
---|
688 | # in list context
|
---|
689 | my ($c,$x,$yorg) = @_;
|
---|
690 |
|
---|
691 | # the general div algorithmn here is about O(N*N) and thus quite slow, so
|
---|
692 | # we first check for some special cases and use shortcuts to handle them.
|
---|
693 |
|
---|
694 | # This works, because we store the numbers in a chunked format where each
|
---|
695 | # element contains 5..7 digits (depending on system).
|
---|
696 |
|
---|
697 | # if both numbers have only one element:
|
---|
698 | if (@$x == 1 && @$yorg == 1)
|
---|
699 | {
|
---|
700 | # shortcut, $yorg and $x are two small numbers
|
---|
701 | if (wantarray)
|
---|
702 | {
|
---|
703 | my $r = [ $x->[0] % $yorg->[0] ];
|
---|
704 | $x->[0] = int($x->[0] / $yorg->[0]);
|
---|
705 | return ($x,$r);
|
---|
706 | }
|
---|
707 | else
|
---|
708 | {
|
---|
709 | $x->[0] = int($x->[0] / $yorg->[0]);
|
---|
710 | return $x;
|
---|
711 | }
|
---|
712 | }
|
---|
713 | # if x has more than one, but y has only one element:
|
---|
714 | if (@$yorg == 1)
|
---|
715 | {
|
---|
716 | my $rem;
|
---|
717 | $rem = _mod($c,[ @$x ],$yorg) if wantarray;
|
---|
718 |
|
---|
719 | # shortcut, $y is < $BASE
|
---|
720 | my $j = scalar @$x; my $r = 0;
|
---|
721 | my $y = $yorg->[0]; my $b;
|
---|
722 | while ($j-- > 0)
|
---|
723 | {
|
---|
724 | $b = $r * $MBASE + $x->[$j];
|
---|
725 | $x->[$j] = int($b/$y);
|
---|
726 | $r = $b % $y;
|
---|
727 | }
|
---|
728 | pop @$x if @$x > 1 && $x->[-1] == 0; # splice up a leading zero
|
---|
729 | return ($x,$rem) if wantarray;
|
---|
730 | return $x;
|
---|
731 | }
|
---|
732 | # now x and y have more than one element
|
---|
733 |
|
---|
734 | # check whether y has more elements than x, if yet, the result will be 0
|
---|
735 | if (@$yorg > @$x)
|
---|
736 | {
|
---|
737 | my $rem;
|
---|
738 | $rem = [@$x] if wantarray; # make copy
|
---|
739 | splice (@$x,1); # keep ref to original array
|
---|
740 | $x->[0] = 0; # set to 0
|
---|
741 | return ($x,$rem) if wantarray; # including remainder?
|
---|
742 | return $x; # only x, which is [0] now
|
---|
743 | }
|
---|
744 | # check whether the numbers have the same number of elements, in that case
|
---|
745 | # the result will fit into one element and can be computed efficiently
|
---|
746 | if (@$yorg == @$x)
|
---|
747 | {
|
---|
748 | my $rem;
|
---|
749 | # if $yorg has more digits than $x (it's leading element is longer than
|
---|
750 | # the one from $x), the result will also be 0:
|
---|
751 | if (length(int($yorg->[-1])) > length(int($x->[-1])))
|
---|
752 | {
|
---|
753 | $rem = [@$x] if wantarray; # make copy
|
---|
754 | splice (@$x,1); # keep ref to org array
|
---|
755 | $x->[0] = 0; # set to 0
|
---|
756 | return ($x,$rem) if wantarray; # including remainder?
|
---|
757 | return $x;
|
---|
758 | }
|
---|
759 | # now calculate $x / $yorg
|
---|
760 |
|
---|
761 | if (length(int($yorg->[-1])) == length(int($x->[-1])))
|
---|
762 | {
|
---|
763 | # same length, so make full compare
|
---|
764 |
|
---|
765 | my $a = 0; my $j = scalar @$x - 1;
|
---|
766 | # manual way (abort if unequal, good for early ne)
|
---|
767 | while ($j >= 0)
|
---|
768 | {
|
---|
769 | last if ($a = $x->[$j] - $yorg->[$j]); $j--;
|
---|
770 | }
|
---|
771 | # $a contains the result of the compare between X and Y
|
---|
772 | # a < 0: x < y, a == 0: x == y, a > 0: x > y
|
---|
773 | if ($a <= 0)
|
---|
774 | {
|
---|
775 | $rem = [ 0 ]; # a = 0 => x == y => rem 0
|
---|
776 | $rem = [@$x] if $a != 0; # a < 0 => x < y => rem = x
|
---|
777 | splice(@$x,1); # keep single element
|
---|
778 | $x->[0] = 0; # if $a < 0
|
---|
779 | $x->[0] = 1 if $a == 0; # $x == $y
|
---|
780 | return ($x,$rem) if wantarray; # including remainder?
|
---|
781 | return $x;
|
---|
782 | }
|
---|
783 | # $x >= $y, so proceed normally
|
---|
784 |
|
---|
785 | }
|
---|
786 | }
|
---|
787 |
|
---|
788 | # all other cases:
|
---|
789 |
|
---|
790 | my $y = [ @$yorg ]; # always make copy to preserve
|
---|
791 |
|
---|
792 | my ($car,$bar,$prd,$dd,$xi,$yi,@q,$v2,$v1,@d,$tmp,$q,$u2,$u1,$u0);
|
---|
793 |
|
---|
794 | $car = $bar = $prd = 0;
|
---|
795 | if (($dd = int($MBASE/($y->[-1]+1))) != 1)
|
---|
796 | {
|
---|
797 | for $xi (@$x)
|
---|
798 | {
|
---|
799 | $xi = $xi * $dd + $car;
|
---|
800 | $xi -= ($car = int($xi / $MBASE)) * $MBASE;
|
---|
801 | }
|
---|
802 | push(@$x, $car); $car = 0;
|
---|
803 | for $yi (@$y)
|
---|
804 | {
|
---|
805 | $yi = $yi * $dd + $car;
|
---|
806 | $yi -= ($car = int($yi / $MBASE)) * $MBASE;
|
---|
807 | }
|
---|
808 | }
|
---|
809 | else
|
---|
810 | {
|
---|
811 | push(@$x, 0);
|
---|
812 | }
|
---|
813 |
|
---|
814 | # @q will accumulate the final result, $q contains the current computed
|
---|
815 | # part of the final result
|
---|
816 |
|
---|
817 | @q = (); ($v2,$v1) = @$y[-2,-1];
|
---|
818 | $v2 = 0 unless $v2;
|
---|
819 | while ($#$x > $#$y)
|
---|
820 | {
|
---|
821 | ($u2,$u1,$u0) = @$x[-3..-1];
|
---|
822 | $u2 = 0 unless $u2;
|
---|
823 | #warn "oups v1 is 0, u0: $u0 $y->[-2] $y->[-1] l ",scalar @$y,"\n"
|
---|
824 | # if $v1 == 0;
|
---|
825 | $q = (($u0 == $v1) ? $MAX_VAL : int(($u0*$MBASE+$u1)/$v1));
|
---|
826 | --$q while ($v2*$q > ($u0*$MBASE+$u1-$q*$v1)*$MBASE+$u2);
|
---|
827 | if ($q)
|
---|
828 | {
|
---|
829 | ($car, $bar) = (0,0);
|
---|
830 | for ($yi = 0, $xi = $#$x-$#$y-1; $yi <= $#$y; ++$yi,++$xi)
|
---|
831 | {
|
---|
832 | $prd = $q * $y->[$yi] + $car;
|
---|
833 | $prd -= ($car = int($prd / $MBASE)) * $MBASE;
|
---|
834 | $x->[$xi] += $MBASE if ($bar = (($x->[$xi] -= $prd + $bar) < 0));
|
---|
835 | }
|
---|
836 | if ($x->[-1] < $car + $bar)
|
---|
837 | {
|
---|
838 | $car = 0; --$q;
|
---|
839 | for ($yi = 0, $xi = $#$x-$#$y-1; $yi <= $#$y; ++$yi,++$xi)
|
---|
840 | {
|
---|
841 | $x->[$xi] -= $MBASE
|
---|
842 | if ($car = (($x->[$xi] += $y->[$yi] + $car) >= $MBASE));
|
---|
843 | }
|
---|
844 | }
|
---|
845 | }
|
---|
846 | pop(@$x); unshift(@q, $q);
|
---|
847 | }
|
---|
848 | if (wantarray)
|
---|
849 | {
|
---|
850 | @d = ();
|
---|
851 | if ($dd != 1)
|
---|
852 | {
|
---|
853 | $car = 0;
|
---|
854 | for $xi (reverse @$x)
|
---|
855 | {
|
---|
856 | $prd = $car * $MBASE + $xi;
|
---|
857 | $car = $prd - ($tmp = int($prd / $dd)) * $dd;
|
---|
858 | unshift(@d, $tmp);
|
---|
859 | }
|
---|
860 | }
|
---|
861 | else
|
---|
862 | {
|
---|
863 | @d = @$x;
|
---|
864 | }
|
---|
865 | @$x = @q;
|
---|
866 | my $d = \@d;
|
---|
867 | __strip_zeros($x);
|
---|
868 | __strip_zeros($d);
|
---|
869 | return ($x,$d);
|
---|
870 | }
|
---|
871 | @$x = @q;
|
---|
872 | __strip_zeros($x);
|
---|
873 | $x;
|
---|
874 | }
|
---|
875 |
|
---|
876 | ##############################################################################
|
---|
877 | # testing
|
---|
878 |
|
---|
879 | sub _acmp
|
---|
880 | {
|
---|
881 | # internal absolute post-normalized compare (ignore signs)
|
---|
882 | # ref to array, ref to array, return <0, 0, >0
|
---|
883 | # arrays must have at least one entry; this is not checked for
|
---|
884 | my ($c,$cx,$cy) = @_;
|
---|
885 |
|
---|
886 | # shortcut for short numbers
|
---|
887 | return (($cx->[0] <=> $cy->[0]) <=> 0)
|
---|
888 | if scalar @$cx == scalar @$cy && scalar @$cx == 1;
|
---|
889 |
|
---|
890 | # fast comp based on number of array elements (aka pseudo-length)
|
---|
891 | my $lxy = (scalar @$cx - scalar @$cy)
|
---|
892 | # or length of first element if same number of elements (aka difference 0)
|
---|
893 | ||
|
---|
894 | # need int() here because sometimes the last element is '00018' vs '18'
|
---|
895 | (length(int($cx->[-1])) - length(int($cy->[-1])));
|
---|
896 | return -1 if $lxy < 0; # already differs, ret
|
---|
897 | return 1 if $lxy > 0; # ditto
|
---|
898 |
|
---|
899 | # manual way (abort if unequal, good for early ne)
|
---|
900 | my $a; my $j = scalar @$cx;
|
---|
901 | while (--$j >= 0)
|
---|
902 | {
|
---|
903 | last if ($a = $cx->[$j] - $cy->[$j]);
|
---|
904 | }
|
---|
905 | $a <=> 0;
|
---|
906 | }
|
---|
907 |
|
---|
908 | sub _len
|
---|
909 | {
|
---|
910 | # compute number of digits
|
---|
911 |
|
---|
912 | # int() because add/sub sometimes leaves strings (like '00005') instead of
|
---|
913 | # '5' in this place, thus causing length() to report wrong length
|
---|
914 | my $cx = $_[1];
|
---|
915 |
|
---|
916 | (@$cx-1)*$BASE_LEN+length(int($cx->[-1]));
|
---|
917 | }
|
---|
918 |
|
---|
919 | sub _digit
|
---|
920 | {
|
---|
921 | # return the nth digit, negative values count backward
|
---|
922 | # zero is rightmost, so _digit(123,0) will give 3
|
---|
923 | my ($c,$x,$n) = @_;
|
---|
924 |
|
---|
925 | my $len = _len('',$x);
|
---|
926 |
|
---|
927 | $n = $len+$n if $n < 0; # -1 last, -2 second-to-last
|
---|
928 | $n = abs($n); # if negative was too big
|
---|
929 | $len--; $n = $len if $n > $len; # n to big?
|
---|
930 |
|
---|
931 | my $elem = int($n / $BASE_LEN); # which array element
|
---|
932 | my $digit = $n % $BASE_LEN; # which digit in this element
|
---|
933 | $elem = '0' x $BASE_LEN . @$x[$elem]; # get element padded with 0's
|
---|
934 | substr($elem,-$digit-1,1);
|
---|
935 | }
|
---|
936 |
|
---|
937 | sub _zeros
|
---|
938 | {
|
---|
939 | # return amount of trailing zeros in decimal
|
---|
940 | # check each array elem in _m for having 0 at end as long as elem == 0
|
---|
941 | # Upon finding a elem != 0, stop
|
---|
942 | my $x = $_[1];
|
---|
943 |
|
---|
944 | return 0 if scalar @$x == 1 && $x->[0] == 0;
|
---|
945 |
|
---|
946 | my $zeros = 0; my $elem;
|
---|
947 | foreach my $e (@$x)
|
---|
948 | {
|
---|
949 | if ($e != 0)
|
---|
950 | {
|
---|
951 | $elem = "$e"; # preserve x
|
---|
952 | $elem =~ s/.*?(0*$)/$1/; # strip anything not zero
|
---|
953 | $zeros *= $BASE_LEN; # elems * 5
|
---|
954 | $zeros += length($elem); # count trailing zeros
|
---|
955 | last; # early out
|
---|
956 | }
|
---|
957 | $zeros ++; # real else branch: 50% slower!
|
---|
958 | }
|
---|
959 | $zeros;
|
---|
960 | }
|
---|
961 |
|
---|
962 | ##############################################################################
|
---|
963 | # _is_* routines
|
---|
964 |
|
---|
965 | sub _is_zero
|
---|
966 | {
|
---|
967 | # return true if arg is zero
|
---|
968 | (((scalar @{$_[1]} == 1) && ($_[1]->[0] == 0))) <=> 0;
|
---|
969 | }
|
---|
970 |
|
---|
971 | sub _is_even
|
---|
972 | {
|
---|
973 | # return true if arg is even
|
---|
974 | (!($_[1]->[0] & 1)) <=> 0;
|
---|
975 | }
|
---|
976 |
|
---|
977 | sub _is_odd
|
---|
978 | {
|
---|
979 | # return true if arg is even
|
---|
980 | (($_[1]->[0] & 1)) <=> 0;
|
---|
981 | }
|
---|
982 |
|
---|
983 | sub _is_one
|
---|
984 | {
|
---|
985 | # return true if arg is one
|
---|
986 | (scalar @{$_[1]} == 1) && ($_[1]->[0] == 1) <=> 0;
|
---|
987 | }
|
---|
988 |
|
---|
989 | sub _is_two
|
---|
990 | {
|
---|
991 | # return true if arg is two
|
---|
992 | (scalar @{$_[1]} == 1) && ($_[1]->[0] == 2) <=> 0;
|
---|
993 | }
|
---|
994 |
|
---|
995 | sub _is_ten
|
---|
996 | {
|
---|
997 | # return true if arg is ten
|
---|
998 | (scalar @{$_[1]} == 1) && ($_[1]->[0] == 10) <=> 0;
|
---|
999 | }
|
---|
1000 |
|
---|
1001 | sub __strip_zeros
|
---|
1002 | {
|
---|
1003 | # internal normalization function that strips leading zeros from the array
|
---|
1004 | # args: ref to array
|
---|
1005 | my $s = shift;
|
---|
1006 |
|
---|
1007 | my $cnt = scalar @$s; # get count of parts
|
---|
1008 | my $i = $cnt-1;
|
---|
1009 | push @$s,0 if $i < 0; # div might return empty results, so fix it
|
---|
1010 |
|
---|
1011 | return $s if @$s == 1; # early out
|
---|
1012 |
|
---|
1013 | #print "strip: cnt $cnt i $i\n";
|
---|
1014 | # '0', '3', '4', '0', '0',
|
---|
1015 | # 0 1 2 3 4
|
---|
1016 | # cnt = 5, i = 4
|
---|
1017 | # i = 4
|
---|
1018 | # i = 3
|
---|
1019 | # => fcnt = cnt - i (5-2 => 3, cnt => 5-1 = 4, throw away from 4th pos)
|
---|
1020 | # >= 1: skip first part (this can be zero)
|
---|
1021 | while ($i > 0) { last if $s->[$i] != 0; $i--; }
|
---|
1022 | $i++; splice @$s,$i if ($i < $cnt); # $i cant be 0
|
---|
1023 | $s;
|
---|
1024 | }
|
---|
1025 |
|
---|
1026 | ###############################################################################
|
---|
1027 | # check routine to test internal state for corruptions
|
---|
1028 |
|
---|
1029 | sub _check
|
---|
1030 | {
|
---|
1031 | # used by the test suite
|
---|
1032 | my $x = $_[1];
|
---|
1033 |
|
---|
1034 | return "$x is not a reference" if !ref($x);
|
---|
1035 |
|
---|
1036 | # are all parts are valid?
|
---|
1037 | my $i = 0; my $j = scalar @$x; my ($e,$try);
|
---|
1038 | while ($i < $j)
|
---|
1039 | {
|
---|
1040 | $e = $x->[$i]; $e = 'undef' unless defined $e;
|
---|
1041 | $try = '=~ /^[\+]?[0-9]+\$/; '."($x, $e)";
|
---|
1042 | last if $e !~ /^[+]?[0-9]+$/;
|
---|
1043 | $try = '=~ /^[\+]?[0-9]+\$/; '."($x, $e) (stringify)";
|
---|
1044 | last if "$e" !~ /^[+]?[0-9]+$/;
|
---|
1045 | $try = '=~ /^[\+]?[0-9]+\$/; '."($x, $e) (cat-stringify)";
|
---|
1046 | last if '' . "$e" !~ /^[+]?[0-9]+$/;
|
---|
1047 | $try = ' < 0 || >= $BASE; '."($x, $e)";
|
---|
1048 | last if $e <0 || $e >= $BASE;
|
---|
1049 | # this test is disabled, since new/bnorm and certain ops (like early out
|
---|
1050 | # in add/sub) are allowed/expected to leave '00000' in some elements
|
---|
1051 | #$try = '=~ /^00+/; '."($x, $e)";
|
---|
1052 | #last if $e =~ /^00+/;
|
---|
1053 | $i++;
|
---|
1054 | }
|
---|
1055 | return "Illegal part '$e' at pos $i (tested: $try)" if $i < $j;
|
---|
1056 | 0;
|
---|
1057 | }
|
---|
1058 |
|
---|
1059 |
|
---|
1060 | ###############################################################################
|
---|
1061 |
|
---|
1062 | sub _mod
|
---|
1063 | {
|
---|
1064 | # if possible, use mod shortcut
|
---|
1065 | my ($c,$x,$yo) = @_;
|
---|
1066 |
|
---|
1067 | # slow way since $y to big
|
---|
1068 | if (scalar @$yo > 1)
|
---|
1069 | {
|
---|
1070 | my ($xo,$rem) = _div($c,$x,$yo);
|
---|
1071 | return $rem;
|
---|
1072 | }
|
---|
1073 |
|
---|
1074 | my $y = $yo->[0];
|
---|
1075 | # both are single element arrays
|
---|
1076 | if (scalar @$x == 1)
|
---|
1077 | {
|
---|
1078 | $x->[0] %= $y;
|
---|
1079 | return $x;
|
---|
1080 | }
|
---|
1081 |
|
---|
1082 | # @y is a single element, but @x has more than one element
|
---|
1083 | my $b = $BASE % $y;
|
---|
1084 | if ($b == 0)
|
---|
1085 | {
|
---|
1086 | # when BASE % Y == 0 then (B * BASE) % Y == 0
|
---|
1087 | # (B * BASE) % $y + A % Y => A % Y
|
---|
1088 | # so need to consider only last element: O(1)
|
---|
1089 | $x->[0] %= $y;
|
---|
1090 | }
|
---|
1091 | elsif ($b == 1)
|
---|
1092 | {
|
---|
1093 | # else need to go through all elements: O(N), but loop is a bit simplified
|
---|
1094 | my $r = 0;
|
---|
1095 | foreach (@$x)
|
---|
1096 | {
|
---|
1097 | $r = ($r + $_) % $y; # not much faster, but heh...
|
---|
1098 | #$r += $_ % $y; $r %= $y;
|
---|
1099 | }
|
---|
1100 | $r = 0 if $r == $y;
|
---|
1101 | $x->[0] = $r;
|
---|
1102 | }
|
---|
1103 | else
|
---|
1104 | {
|
---|
1105 | # else need to go through all elements: O(N)
|
---|
1106 | my $r = 0; my $bm = 1;
|
---|
1107 | foreach (@$x)
|
---|
1108 | {
|
---|
1109 | $r = ($_ * $bm + $r) % $y;
|
---|
1110 | $bm = ($bm * $b) % $y;
|
---|
1111 |
|
---|
1112 | #$r += ($_ % $y) * $bm;
|
---|
1113 | #$bm *= $b;
|
---|
1114 | #$bm %= $y;
|
---|
1115 | #$r %= $y;
|
---|
1116 | }
|
---|
1117 | $r = 0 if $r == $y;
|
---|
1118 | $x->[0] = $r;
|
---|
1119 | }
|
---|
1120 | splice (@$x,1); # keep one element of $x
|
---|
1121 | $x;
|
---|
1122 | }
|
---|
1123 |
|
---|
1124 | ##############################################################################
|
---|
1125 | # shifts
|
---|
1126 |
|
---|
1127 | sub _rsft
|
---|
1128 | {
|
---|
1129 | my ($c,$x,$y,$n) = @_;
|
---|
1130 |
|
---|
1131 | if ($n != 10)
|
---|
1132 | {
|
---|
1133 | $n = _new($c,$n); return _div($c,$x, _pow($c,$n,$y));
|
---|
1134 | }
|
---|
1135 |
|
---|
1136 | # shortcut (faster) for shifting by 10)
|
---|
1137 | # multiples of $BASE_LEN
|
---|
1138 | my $dst = 0; # destination
|
---|
1139 | my $src = _num($c,$y); # as normal int
|
---|
1140 | my $xlen = (@$x-1)*$BASE_LEN+length(int($x->[-1])); # len of x in digits
|
---|
1141 | if ($src >= $xlen or ($src == $xlen and ! defined $x->[1]))
|
---|
1142 | {
|
---|
1143 | # 12345 67890 shifted right by more than 10 digits => 0
|
---|
1144 | splice (@$x,1); # leave only one element
|
---|
1145 | $x->[0] = 0; # set to zero
|
---|
1146 | return $x;
|
---|
1147 | }
|
---|
1148 | my $rem = $src % $BASE_LEN; # remainder to shift
|
---|
1149 | $src = int($src / $BASE_LEN); # source
|
---|
1150 | if ($rem == 0)
|
---|
1151 | {
|
---|
1152 | splice (@$x,0,$src); # even faster, 38.4 => 39.3
|
---|
1153 | }
|
---|
1154 | else
|
---|
1155 | {
|
---|
1156 | my $len = scalar @$x - $src; # elems to go
|
---|
1157 | my $vd; my $z = '0'x $BASE_LEN;
|
---|
1158 | $x->[scalar @$x] = 0; # avoid || 0 test inside loop
|
---|
1159 | while ($dst < $len)
|
---|
1160 | {
|
---|
1161 | $vd = $z.$x->[$src];
|
---|
1162 | $vd = substr($vd,-$BASE_LEN,$BASE_LEN-$rem);
|
---|
1163 | $src++;
|
---|
1164 | $vd = substr($z.$x->[$src],-$rem,$rem) . $vd;
|
---|
1165 | $vd = substr($vd,-$BASE_LEN,$BASE_LEN) if length($vd) > $BASE_LEN;
|
---|
1166 | $x->[$dst] = int($vd);
|
---|
1167 | $dst++;
|
---|
1168 | }
|
---|
1169 | splice (@$x,$dst) if $dst > 0; # kill left-over array elems
|
---|
1170 | pop @$x if $x->[-1] == 0 && @$x > 1; # kill last element if 0
|
---|
1171 | } # else rem == 0
|
---|
1172 | $x;
|
---|
1173 | }
|
---|
1174 |
|
---|
1175 | sub _lsft
|
---|
1176 | {
|
---|
1177 | my ($c,$x,$y,$n) = @_;
|
---|
1178 |
|
---|
1179 | if ($n != 10)
|
---|
1180 | {
|
---|
1181 | $n = _new($c,$n); return _mul($c,$x, _pow($c,$n,$y));
|
---|
1182 | }
|
---|
1183 |
|
---|
1184 | # shortcut (faster) for shifting by 10) since we are in base 10eX
|
---|
1185 | # multiples of $BASE_LEN:
|
---|
1186 | my $src = scalar @$x; # source
|
---|
1187 | my $len = _num($c,$y); # shift-len as normal int
|
---|
1188 | my $rem = $len % $BASE_LEN; # remainder to shift
|
---|
1189 | my $dst = $src + int($len/$BASE_LEN); # destination
|
---|
1190 | my $vd; # further speedup
|
---|
1191 | $x->[$src] = 0; # avoid first ||0 for speed
|
---|
1192 | my $z = '0' x $BASE_LEN;
|
---|
1193 | while ($src >= 0)
|
---|
1194 | {
|
---|
1195 | $vd = $x->[$src]; $vd = $z.$vd;
|
---|
1196 | $vd = substr($vd,-$BASE_LEN+$rem,$BASE_LEN-$rem);
|
---|
1197 | $vd .= $src > 0 ? substr($z.$x->[$src-1],-$BASE_LEN,$rem) : '0' x $rem;
|
---|
1198 | $vd = substr($vd,-$BASE_LEN,$BASE_LEN) if length($vd) > $BASE_LEN;
|
---|
1199 | $x->[$dst] = int($vd);
|
---|
1200 | $dst--; $src--;
|
---|
1201 | }
|
---|
1202 | # set lowest parts to 0
|
---|
1203 | while ($dst >= 0) { $x->[$dst--] = 0; }
|
---|
1204 | # fix spurios last zero element
|
---|
1205 | splice @$x,-1 if $x->[-1] == 0;
|
---|
1206 | $x;
|
---|
1207 | }
|
---|
1208 |
|
---|
1209 | sub _pow
|
---|
1210 | {
|
---|
1211 | # power of $x to $y
|
---|
1212 | # ref to array, ref to array, return ref to array
|
---|
1213 | my ($c,$cx,$cy) = @_;
|
---|
1214 |
|
---|
1215 | if (scalar @$cy == 1 && $cy->[0] == 0)
|
---|
1216 | {
|
---|
1217 | splice (@$cx,1); $cx->[0] = 1; # y == 0 => x => 1
|
---|
1218 | return $cx;
|
---|
1219 | }
|
---|
1220 | if ((scalar @$cx == 1 && $cx->[0] == 1) || # x == 1
|
---|
1221 | (scalar @$cy == 1 && $cy->[0] == 1)) # or y == 1
|
---|
1222 | {
|
---|
1223 | return $cx;
|
---|
1224 | }
|
---|
1225 | if (scalar @$cx == 1 && $cx->[0] == 0)
|
---|
1226 | {
|
---|
1227 | splice (@$cx,1); $cx->[0] = 0; # 0 ** y => 0 (if not y <= 0)
|
---|
1228 | return $cx;
|
---|
1229 | }
|
---|
1230 |
|
---|
1231 | my $pow2 = _one();
|
---|
1232 |
|
---|
1233 | my $y_bin = _as_bin($c,$cy); $y_bin =~ s/^0b//;
|
---|
1234 | my $len = length($y_bin);
|
---|
1235 | while (--$len > 0)
|
---|
1236 | {
|
---|
1237 | _mul($c,$pow2,$cx) if substr($y_bin,$len,1) eq '1'; # is odd?
|
---|
1238 | _mul($c,$cx,$cx);
|
---|
1239 | }
|
---|
1240 |
|
---|
1241 | _mul($c,$cx,$pow2);
|
---|
1242 | $cx;
|
---|
1243 | }
|
---|
1244 |
|
---|
1245 | sub _fac
|
---|
1246 | {
|
---|
1247 | # factorial of $x
|
---|
1248 | # ref to array, return ref to array
|
---|
1249 | my ($c,$cx) = @_;
|
---|
1250 |
|
---|
1251 | if ((@$cx == 1) && ($cx->[0] <= 2))
|
---|
1252 | {
|
---|
1253 | $cx->[0] ||= 1; # 0 => 1, 1 => 1, 2 => 2
|
---|
1254 | return $cx;
|
---|
1255 | }
|
---|
1256 |
|
---|
1257 | # go forward until $base is exceeded
|
---|
1258 | # limit is either $x steps (steps == 100 means a result always too high) or
|
---|
1259 | # $base.
|
---|
1260 | my $steps = 100; $steps = $cx->[0] if @$cx == 1;
|
---|
1261 | my $r = 2; my $cf = 3; my $step = 2; my $last = $r;
|
---|
1262 | while ($r*$cf < $BASE && $step < $steps)
|
---|
1263 | {
|
---|
1264 | $last = $r; $r *= $cf++; $step++;
|
---|
1265 | }
|
---|
1266 | if ((@$cx == 1) && $step == $cx->[0])
|
---|
1267 | {
|
---|
1268 | # completely done, so keep reference to $x and return
|
---|
1269 | $cx->[0] = $r;
|
---|
1270 | return $cx;
|
---|
1271 | }
|
---|
1272 |
|
---|
1273 | # now we must do the left over steps
|
---|
1274 | my $n; # steps still to do
|
---|
1275 | if (scalar @$cx == 1)
|
---|
1276 | {
|
---|
1277 | $n = $cx->[0];
|
---|
1278 | }
|
---|
1279 | else
|
---|
1280 | {
|
---|
1281 | $n = _copy($c,$cx);
|
---|
1282 | }
|
---|
1283 |
|
---|
1284 | $cx->[0] = $last; splice (@$cx,1); # keep ref to $x
|
---|
1285 | my $zero_elements = 0;
|
---|
1286 |
|
---|
1287 | # do left-over steps fit into a scalar?
|
---|
1288 | if (ref $n eq 'ARRAY')
|
---|
1289 | {
|
---|
1290 | # No, so use slower inc() & cmp()
|
---|
1291 | $step = [$step];
|
---|
1292 | while (_acmp($step,$n) <= 0)
|
---|
1293 | {
|
---|
1294 | # as soon as the last element of $cx is 0, we split it up and remember
|
---|
1295 | # how many zeors we got so far. The reason is that n! will accumulate
|
---|
1296 | # zeros at the end rather fast.
|
---|
1297 | if ($cx->[0] == 0)
|
---|
1298 | {
|
---|
1299 | $zero_elements ++; shift @$cx;
|
---|
1300 | }
|
---|
1301 | _mul($c,$cx,$step); _inc($c,$step);
|
---|
1302 | }
|
---|
1303 | }
|
---|
1304 | else
|
---|
1305 | {
|
---|
1306 | # Yes, so we can speed it up slightly
|
---|
1307 | while ($step <= $n)
|
---|
1308 | {
|
---|
1309 | # When the last element of $cx is 0, we split it up and remember
|
---|
1310 | # how many we got so far. The reason is that n! will accumulate
|
---|
1311 | # zeros at the end rather fast.
|
---|
1312 | if ($cx->[0] == 0)
|
---|
1313 | {
|
---|
1314 | $zero_elements ++; shift @$cx;
|
---|
1315 | }
|
---|
1316 | _mul($c,$cx,[$step]); $step++;
|
---|
1317 | }
|
---|
1318 | }
|
---|
1319 | # multiply in the zeros again
|
---|
1320 | while ($zero_elements-- > 0)
|
---|
1321 | {
|
---|
1322 | unshift @$cx, 0;
|
---|
1323 | }
|
---|
1324 | $cx; # return result
|
---|
1325 | }
|
---|
1326 |
|
---|
1327 | #############################################################################
|
---|
1328 |
|
---|
1329 | sub _log_int
|
---|
1330 | {
|
---|
1331 | # calculate integer log of $x to base $base
|
---|
1332 | # ref to array, ref to array - return ref to array
|
---|
1333 | my ($c,$x,$base) = @_;
|
---|
1334 |
|
---|
1335 | # X == 0 => NaN
|
---|
1336 | return if (scalar @$x == 1 && $x->[0] == 0);
|
---|
1337 | # BASE 0 or 1 => NaN
|
---|
1338 | return if (scalar @$base == 1 && $base->[0] < 2);
|
---|
1339 | my $cmp = _acmp($c,$x,$base); # X == BASE => 1
|
---|
1340 | if ($cmp == 0)
|
---|
1341 | {
|
---|
1342 | splice (@$x,1); $x->[0] = 1;
|
---|
1343 | return ($x,1)
|
---|
1344 | }
|
---|
1345 | # X < BASE
|
---|
1346 | if ($cmp < 0)
|
---|
1347 | {
|
---|
1348 | splice (@$x,1); $x->[0] = 0;
|
---|
1349 | return ($x,undef);
|
---|
1350 | }
|
---|
1351 |
|
---|
1352 | # this trial multiplication is very fast, even for large counts (like for
|
---|
1353 | # 2 ** 1024, since this still requires only 1024 very fast steps
|
---|
1354 | # (multiplication of a large number by a very small number is very fast))
|
---|
1355 | my $x_org = _copy($c,$x); # preserve x
|
---|
1356 | splice(@$x,1); $x->[0] = 1; # keep ref to $x
|
---|
1357 |
|
---|
1358 | my $trial = _copy($c,$base);
|
---|
1359 |
|
---|
1360 | # XXX TODO this only works if $base has only one element
|
---|
1361 | if (scalar @$base == 1)
|
---|
1362 | {
|
---|
1363 | # compute int ( length_in_base_10(X) / ( log(base) / log(10) ) )
|
---|
1364 | my $len = _len($c,$x_org);
|
---|
1365 | my $res = int($len / (log($base->[0]) / log(10))) || 1; # avoid $res == 0
|
---|
1366 |
|
---|
1367 | $x->[0] = $res;
|
---|
1368 | $trial = _pow ($c, _copy($c, $base), $x);
|
---|
1369 | my $a = _acmp($x,$trial,$x_org);
|
---|
1370 | return ($x,1) if $a == 0;
|
---|
1371 | # we now know that $res is too small
|
---|
1372 | if ($res < 0)
|
---|
1373 | {
|
---|
1374 | _mul($c,$trial,$base); _add($c, $x, [1]);
|
---|
1375 | }
|
---|
1376 | else
|
---|
1377 | {
|
---|
1378 | # or too big
|
---|
1379 | _div($c,$trial,$base); _sub($c, $x, [1]);
|
---|
1380 | }
|
---|
1381 | # did we now get the right result?
|
---|
1382 | $a = _acmp($x,$trial,$x_org);
|
---|
1383 | return ($x,1) if $a == 0; # yes, exactly
|
---|
1384 | # still too big
|
---|
1385 | if ($a > 0)
|
---|
1386 | {
|
---|
1387 | _div($c,$trial,$base); _sub($c, $x, [1]);
|
---|
1388 | }
|
---|
1389 | }
|
---|
1390 |
|
---|
1391 | # simple loop that increments $x by two in each step, possible overstepping
|
---|
1392 | # the real result by one
|
---|
1393 |
|
---|
1394 | my $a;
|
---|
1395 | my $base_mul = _mul($c, _copy($c,$base), $base);
|
---|
1396 |
|
---|
1397 | while (($a = _acmp($c,$trial,$x_org)) < 0)
|
---|
1398 | {
|
---|
1399 | _mul($c,$trial,$base_mul); _add($c, $x, [2]);
|
---|
1400 | }
|
---|
1401 |
|
---|
1402 | my $exact = 1;
|
---|
1403 | if ($a > 0)
|
---|
1404 | {
|
---|
1405 | # overstepped the result
|
---|
1406 | _dec($c, $x);
|
---|
1407 | _div($c,$trial,$base);
|
---|
1408 | $a = _acmp($c,$trial,$x_org);
|
---|
1409 | if ($a > 0)
|
---|
1410 | {
|
---|
1411 | _dec($c, $x);
|
---|
1412 | }
|
---|
1413 | $exact = 0 if $a != 0;
|
---|
1414 | }
|
---|
1415 |
|
---|
1416 | ($x,$exact); # return result
|
---|
1417 | }
|
---|
1418 |
|
---|
1419 | # for debugging:
|
---|
1420 | use constant DEBUG => 0;
|
---|
1421 | my $steps = 0;
|
---|
1422 | sub steps { $steps };
|
---|
1423 |
|
---|
1424 | sub _sqrt
|
---|
1425 | {
|
---|
1426 | # square-root of $x in place
|
---|
1427 | # Compute a guess of the result (by rule of thumb), then improve it via
|
---|
1428 | # Newton's method.
|
---|
1429 | my ($c,$x) = @_;
|
---|
1430 |
|
---|
1431 | if (scalar @$x == 1)
|
---|
1432 | {
|
---|
1433 | # fit's into one Perl scalar, so result can be computed directly
|
---|
1434 | $x->[0] = int(sqrt($x->[0]));
|
---|
1435 | return $x;
|
---|
1436 | }
|
---|
1437 | my $y = _copy($c,$x);
|
---|
1438 | # hopefully _len/2 is < $BASE, the -1 is to always undershot the guess
|
---|
1439 | # since our guess will "grow"
|
---|
1440 | my $l = int((_len($c,$x)-1) / 2);
|
---|
1441 |
|
---|
1442 | my $lastelem = $x->[-1]; # for guess
|
---|
1443 | my $elems = scalar @$x - 1;
|
---|
1444 | # not enough digits, but could have more?
|
---|
1445 | if ((length($lastelem) <= 3) && ($elems > 1))
|
---|
1446 | {
|
---|
1447 | # right-align with zero pad
|
---|
1448 | my $len = length($lastelem) & 1;
|
---|
1449 | print "$lastelem => " if DEBUG;
|
---|
1450 | $lastelem .= substr($x->[-2] . '0' x $BASE_LEN,0,$BASE_LEN);
|
---|
1451 | # former odd => make odd again, or former even to even again
|
---|
1452 | $lastelem = $lastelem / 10 if (length($lastelem) & 1) != $len;
|
---|
1453 | print "$lastelem\n" if DEBUG;
|
---|
1454 | }
|
---|
1455 |
|
---|
1456 | # construct $x (instead of _lsft($c,$x,$l,10)
|
---|
1457 | my $r = $l % $BASE_LEN; # 10000 00000 00000 00000 ($BASE_LEN=5)
|
---|
1458 | $l = int($l / $BASE_LEN);
|
---|
1459 | print "l = $l " if DEBUG;
|
---|
1460 |
|
---|
1461 | splice @$x,$l; # keep ref($x), but modify it
|
---|
1462 |
|
---|
1463 | # we make the first part of the guess not '1000...0' but int(sqrt($lastelem))
|
---|
1464 | # that gives us:
|
---|
1465 | # 14400 00000 => sqrt(14400) => guess first digits to be 120
|
---|
1466 | # 144000 000000 => sqrt(144000) => guess 379
|
---|
1467 |
|
---|
1468 | print "$lastelem (elems $elems) => " if DEBUG;
|
---|
1469 | $lastelem = $lastelem / 10 if ($elems & 1 == 1); # odd or even?
|
---|
1470 | my $g = sqrt($lastelem); $g =~ s/\.//; # 2.345 => 2345
|
---|
1471 | $r -= 1 if $elems & 1 == 0; # 70 => 7
|
---|
1472 |
|
---|
1473 | # padd with zeros if result is too short
|
---|
1474 | $x->[$l--] = int(substr($g . '0' x $r,0,$r+1));
|
---|
1475 | print "now ",$x->[-1] if DEBUG;
|
---|
1476 | print " would have been ", int('1' . '0' x $r),"\n" if DEBUG;
|
---|
1477 |
|
---|
1478 | # If @$x > 1, we could compute the second elem of the guess, too, to create
|
---|
1479 | # an even better guess. Not implemented yet. Does it improve performance?
|
---|
1480 | $x->[$l--] = 0 while ($l >= 0); # all other digits of guess are zero
|
---|
1481 |
|
---|
1482 | print "start x= ",_str($c,$x),"\n" if DEBUG;
|
---|
1483 | my $two = _two();
|
---|
1484 | my $last = _zero();
|
---|
1485 | my $lastlast = _zero();
|
---|
1486 | $steps = 0 if DEBUG;
|
---|
1487 | while (_acmp($c,$last,$x) != 0 && _acmp($c,$lastlast,$x) != 0)
|
---|
1488 | {
|
---|
1489 | $steps++ if DEBUG;
|
---|
1490 | $lastlast = _copy($c,$last);
|
---|
1491 | $last = _copy($c,$x);
|
---|
1492 | _add($c,$x, _div($c,_copy($c,$y),$x));
|
---|
1493 | _div($c,$x, $two );
|
---|
1494 | print " x= ",_str($c,$x),"\n" if DEBUG;
|
---|
1495 | }
|
---|
1496 | print "\nsteps in sqrt: $steps, " if DEBUG;
|
---|
1497 | _dec($c,$x) if _acmp($c,$y,_mul($c,_copy($c,$x),$x)) < 0; # overshot?
|
---|
1498 | print " final ",$x->[-1],"\n" if DEBUG;
|
---|
1499 | $x;
|
---|
1500 | }
|
---|
1501 |
|
---|
1502 | sub _root
|
---|
1503 | {
|
---|
1504 | # take n'th root of $x in place (n >= 3)
|
---|
1505 | my ($c,$x,$n) = @_;
|
---|
1506 |
|
---|
1507 | if (scalar @$x == 1)
|
---|
1508 | {
|
---|
1509 | if (scalar @$n > 1)
|
---|
1510 | {
|
---|
1511 | # result will always be smaller than 2 so trunc to 1 at once
|
---|
1512 | $x->[0] = 1;
|
---|
1513 | }
|
---|
1514 | else
|
---|
1515 | {
|
---|
1516 | # fit's into one Perl scalar, so result can be computed directly
|
---|
1517 | # cannot use int() here, because it rounds wrongly (try
|
---|
1518 | # (81 ** 3) ** (1/3) to see what I mean)
|
---|
1519 | #$x->[0] = int( $x->[0] ** (1 / $n->[0]) );
|
---|
1520 | # round to 8 digits, then truncate result to integer
|
---|
1521 | $x->[0] = int ( sprintf ("%.8f", $x->[0] ** (1 / $n->[0]) ) );
|
---|
1522 | }
|
---|
1523 | return $x;
|
---|
1524 | }
|
---|
1525 |
|
---|
1526 | # we know now that X is more than one element long
|
---|
1527 |
|
---|
1528 | # if $n is a power of two, we can repeatedly take sqrt($X) and find the
|
---|
1529 | # proper result, because sqrt(sqrt($x)) == root($x,4)
|
---|
1530 | my $b = _as_bin($c,$n);
|
---|
1531 | if ($b =~ /0b1(0+)$/)
|
---|
1532 | {
|
---|
1533 | my $count = CORE::length($1); # 0b100 => len('00') => 2
|
---|
1534 | my $cnt = $count; # counter for loop
|
---|
1535 | unshift (@$x, 0); # add one element, together with one
|
---|
1536 | # more below in the loop this makes 2
|
---|
1537 | while ($cnt-- > 0)
|
---|
1538 | {
|
---|
1539 | # 'inflate' $X by adding one element, basically computing
|
---|
1540 | # $x * $BASE * $BASE. This gives us more $BASE_LEN digits for result
|
---|
1541 | # since len(sqrt($X)) approx == len($x) / 2.
|
---|
1542 | unshift (@$x, 0);
|
---|
1543 | # calculate sqrt($x), $x is now one element to big, again. In the next
|
---|
1544 | # round we make that two, again.
|
---|
1545 | _sqrt($c,$x);
|
---|
1546 | }
|
---|
1547 | # $x is now one element to big, so truncate result by removing it
|
---|
1548 | splice (@$x,0,1);
|
---|
1549 | }
|
---|
1550 | else
|
---|
1551 | {
|
---|
1552 | # trial computation by starting with 2,4,8,16 etc until we overstep
|
---|
1553 | my $step;
|
---|
1554 | my $trial = _two();
|
---|
1555 |
|
---|
1556 | # while still to do more than X steps
|
---|
1557 | do
|
---|
1558 | {
|
---|
1559 | $step = _two();
|
---|
1560 | while (_acmp($c, _pow($c, _copy($c, $trial), $n), $x) < 0)
|
---|
1561 | {
|
---|
1562 | _mul ($c, $step, [2]);
|
---|
1563 | _add ($c, $trial, $step);
|
---|
1564 | }
|
---|
1565 |
|
---|
1566 | # hit exactly?
|
---|
1567 | if (_acmp($c, _pow($c, _copy($c, $trial), $n), $x) == 0)
|
---|
1568 | {
|
---|
1569 | @$x = @$trial; # make copy while preserving ref to $x
|
---|
1570 | return $x;
|
---|
1571 | }
|
---|
1572 | # overstepped, so go back on step
|
---|
1573 | _sub($c, $trial, $step);
|
---|
1574 | } while (scalar @$step > 1 || $step->[0] > 128);
|
---|
1575 |
|
---|
1576 | # reset step to 2
|
---|
1577 | $step = _two();
|
---|
1578 | # add two, because $trial cannot be exactly the result (otherwise we would
|
---|
1579 | # alrady have found it)
|
---|
1580 | _add($c, $trial, $step);
|
---|
1581 |
|
---|
1582 | # and now add more and more (2,4,6,8,10 etc)
|
---|
1583 | while (_acmp($c, _pow($c, _copy($c, $trial), $n), $x) < 0)
|
---|
1584 | {
|
---|
1585 | _add ($c, $trial, $step);
|
---|
1586 | }
|
---|
1587 |
|
---|
1588 | # hit not exactly? (overstepped)
|
---|
1589 | if (_acmp($c, _pow($c, _copy($c, $trial), $n), $x) > 0)
|
---|
1590 | {
|
---|
1591 | _dec($c,$trial);
|
---|
1592 | }
|
---|
1593 |
|
---|
1594 | # hit not exactly? (overstepped)
|
---|
1595 | # 80 too small, 81 slightly too big, 82 too big
|
---|
1596 | if (_acmp($c, _pow($c, _copy($c, $trial), $n), $x) > 0)
|
---|
1597 | {
|
---|
1598 | _dec ($c, $trial);
|
---|
1599 | }
|
---|
1600 |
|
---|
1601 | @$x = @$trial; # make copy while preserving ref to $x
|
---|
1602 | return $x;
|
---|
1603 | }
|
---|
1604 | $x;
|
---|
1605 | }
|
---|
1606 |
|
---|
1607 | ##############################################################################
|
---|
1608 | # binary stuff
|
---|
1609 |
|
---|
1610 | sub _and
|
---|
1611 | {
|
---|
1612 | my ($c,$x,$y) = @_;
|
---|
1613 |
|
---|
1614 | # the shortcut makes equal, large numbers _really_ fast, and makes only a
|
---|
1615 | # very small performance drop for small numbers (e.g. something with less
|
---|
1616 | # than 32 bit) Since we optimize for large numbers, this is enabled.
|
---|
1617 | return $x if _acmp($c,$x,$y) == 0; # shortcut
|
---|
1618 |
|
---|
1619 | my $m = _one(); my ($xr,$yr);
|
---|
1620 | my $mask = $AND_MASK;
|
---|
1621 |
|
---|
1622 | my $x1 = $x;
|
---|
1623 | my $y1 = _copy($c,$y); # make copy
|
---|
1624 | $x = _zero();
|
---|
1625 | my ($b,$xrr,$yrr);
|
---|
1626 | use integer;
|
---|
1627 | while (!_is_zero($c,$x1) && !_is_zero($c,$y1))
|
---|
1628 | {
|
---|
1629 | ($x1, $xr) = _div($c,$x1,$mask);
|
---|
1630 | ($y1, $yr) = _div($c,$y1,$mask);
|
---|
1631 |
|
---|
1632 | # make ints() from $xr, $yr
|
---|
1633 | # this is when the AND_BITS are greater than $BASE and is slower for
|
---|
1634 | # small (<256 bits) numbers, but faster for large numbers. Disabled
|
---|
1635 | # due to KISS principle
|
---|
1636 |
|
---|
1637 | # $b = 1; $xrr = 0; foreach (@$xr) { $xrr += $_ * $b; $b *= $BASE; }
|
---|
1638 | # $b = 1; $yrr = 0; foreach (@$yr) { $yrr += $_ * $b; $b *= $BASE; }
|
---|
1639 | # _add($c,$x, _mul($c, _new( $c, ($xrr & $yrr) ), $m) );
|
---|
1640 |
|
---|
1641 | # 0+ due to '&' doesn't work in strings
|
---|
1642 | _add($c,$x, _mul($c, [ 0+$xr->[0] & 0+$yr->[0] ], $m) );
|
---|
1643 | _mul($c,$m,$mask);
|
---|
1644 | }
|
---|
1645 | $x;
|
---|
1646 | }
|
---|
1647 |
|
---|
1648 | sub _xor
|
---|
1649 | {
|
---|
1650 | my ($c,$x,$y) = @_;
|
---|
1651 |
|
---|
1652 | return _zero() if _acmp($c,$x,$y) == 0; # shortcut (see -and)
|
---|
1653 |
|
---|
1654 | my $m = _one(); my ($xr,$yr);
|
---|
1655 | my $mask = $XOR_MASK;
|
---|
1656 |
|
---|
1657 | my $x1 = $x;
|
---|
1658 | my $y1 = _copy($c,$y); # make copy
|
---|
1659 | $x = _zero();
|
---|
1660 | my ($b,$xrr,$yrr);
|
---|
1661 | use integer;
|
---|
1662 | while (!_is_zero($c,$x1) && !_is_zero($c,$y1))
|
---|
1663 | {
|
---|
1664 | ($x1, $xr) = _div($c,$x1,$mask);
|
---|
1665 | ($y1, $yr) = _div($c,$y1,$mask);
|
---|
1666 | # make ints() from $xr, $yr (see _and())
|
---|
1667 | #$b = 1; $xrr = 0; foreach (@$xr) { $xrr += $_ * $b; $b *= $BASE; }
|
---|
1668 | #$b = 1; $yrr = 0; foreach (@$yr) { $yrr += $_ * $b; $b *= $BASE; }
|
---|
1669 | #_add($c,$x, _mul($c, _new( $c, ($xrr ^ $yrr) ), $m) );
|
---|
1670 |
|
---|
1671 | # 0+ due to '^' doesn't work in strings
|
---|
1672 | _add($c,$x, _mul($c, [ 0+$xr->[0] ^ 0+$yr->[0] ], $m) );
|
---|
1673 | _mul($c,$m,$mask);
|
---|
1674 | }
|
---|
1675 | # the loop stops when the shorter of the two numbers is exhausted
|
---|
1676 | # the remainder of the longer one will survive bit-by-bit, so we simple
|
---|
1677 | # multiply-add it in
|
---|
1678 | _add($c,$x, _mul($c, $x1, $m) ) if !_is_zero($c,$x1);
|
---|
1679 | _add($c,$x, _mul($c, $y1, $m) ) if !_is_zero($c,$y1);
|
---|
1680 |
|
---|
1681 | $x;
|
---|
1682 | }
|
---|
1683 |
|
---|
1684 | sub _or
|
---|
1685 | {
|
---|
1686 | my ($c,$x,$y) = @_;
|
---|
1687 |
|
---|
1688 | return $x if _acmp($c,$x,$y) == 0; # shortcut (see _and)
|
---|
1689 |
|
---|
1690 | my $m = _one(); my ($xr,$yr);
|
---|
1691 | my $mask = $OR_MASK;
|
---|
1692 |
|
---|
1693 | my $x1 = $x;
|
---|
1694 | my $y1 = _copy($c,$y); # make copy
|
---|
1695 | $x = _zero();
|
---|
1696 | my ($b,$xrr,$yrr);
|
---|
1697 | use integer;
|
---|
1698 | while (!_is_zero($c,$x1) && !_is_zero($c,$y1))
|
---|
1699 | {
|
---|
1700 | ($x1, $xr) = _div($c,$x1,$mask);
|
---|
1701 | ($y1, $yr) = _div($c,$y1,$mask);
|
---|
1702 | # make ints() from $xr, $yr (see _and())
|
---|
1703 | # $b = 1; $xrr = 0; foreach (@$xr) { $xrr += $_ * $b; $b *= $BASE; }
|
---|
1704 | # $b = 1; $yrr = 0; foreach (@$yr) { $yrr += $_ * $b; $b *= $BASE; }
|
---|
1705 | # _add($c,$x, _mul($c, _new( $c, ($xrr | $yrr) ), $m) );
|
---|
1706 |
|
---|
1707 | # 0+ due to '|' doesn't work in strings
|
---|
1708 | _add($c,$x, _mul($c, [ 0+$xr->[0] | 0+$yr->[0] ], $m) );
|
---|
1709 | _mul($c,$m,$mask);
|
---|
1710 | }
|
---|
1711 | # the loop stops when the shorter of the two numbers is exhausted
|
---|
1712 | # the remainder of the longer one will survive bit-by-bit, so we simple
|
---|
1713 | # multiply-add it in
|
---|
1714 | _add($c,$x, _mul($c, $x1, $m) ) if !_is_zero($c,$x1);
|
---|
1715 | _add($c,$x, _mul($c, $y1, $m) ) if !_is_zero($c,$y1);
|
---|
1716 |
|
---|
1717 | $x;
|
---|
1718 | }
|
---|
1719 |
|
---|
1720 | sub _as_hex
|
---|
1721 | {
|
---|
1722 | # convert a decimal number to hex (ref to array, return ref to string)
|
---|
1723 | my ($c,$x) = @_;
|
---|
1724 |
|
---|
1725 | # fit's into one element (handle also 0x0 case)
|
---|
1726 | return sprintf("0x%x",$x->[0]) if @$x == 1;
|
---|
1727 |
|
---|
1728 | my $x1 = _copy($c,$x);
|
---|
1729 |
|
---|
1730 | my $es = '';
|
---|
1731 | my ($xr, $h, $x10000);
|
---|
1732 | if ($] >= 5.006)
|
---|
1733 | {
|
---|
1734 | $x10000 = [ 0x10000 ]; $h = 'h4';
|
---|
1735 | }
|
---|
1736 | else
|
---|
1737 | {
|
---|
1738 | $x10000 = [ 0x1000 ]; $h = 'h3';
|
---|
1739 | }
|
---|
1740 | while (@$x1 != 1 || $x1->[0] != 0) # _is_zero()
|
---|
1741 | {
|
---|
1742 | ($x1, $xr) = _div($c,$x1,$x10000);
|
---|
1743 | $es .= unpack($h,pack('v',$xr->[0])); # XXX TODO: why pack('v',...)?
|
---|
1744 | }
|
---|
1745 | $es = reverse $es;
|
---|
1746 | $es =~ s/^[0]+//; # strip leading zeros
|
---|
1747 | '0x' . $es; # return result prepended with 0x
|
---|
1748 | }
|
---|
1749 |
|
---|
1750 | sub _as_bin
|
---|
1751 | {
|
---|
1752 | # convert a decimal number to bin (ref to array, return ref to string)
|
---|
1753 | my ($c,$x) = @_;
|
---|
1754 |
|
---|
1755 | # fit's into one element (and Perl recent enough), handle also 0b0 case
|
---|
1756 | # handle zero case for older Perls
|
---|
1757 | if ($] <= 5.005 && @$x == 1 && $x->[0] == 0)
|
---|
1758 | {
|
---|
1759 | my $t = '0b0'; return $t;
|
---|
1760 | }
|
---|
1761 | if (@$x == 1 && $] >= 5.006)
|
---|
1762 | {
|
---|
1763 | my $t = sprintf("0b%b",$x->[0]);
|
---|
1764 | return $t;
|
---|
1765 | }
|
---|
1766 | my $x1 = _copy($c,$x);
|
---|
1767 |
|
---|
1768 | my $es = '';
|
---|
1769 | my ($xr, $b, $x10000);
|
---|
1770 | if ($] >= 5.006)
|
---|
1771 | {
|
---|
1772 | $x10000 = [ 0x10000 ]; $b = 'b16';
|
---|
1773 | }
|
---|
1774 | else
|
---|
1775 | {
|
---|
1776 | $x10000 = [ 0x1000 ]; $b = 'b12';
|
---|
1777 | }
|
---|
1778 | while (!(@$x1 == 1 && $x1->[0] == 0)) # _is_zero()
|
---|
1779 | {
|
---|
1780 | ($x1, $xr) = _div($c,$x1,$x10000);
|
---|
1781 | $es .= unpack($b,pack('v',$xr->[0])); # XXX TODO: why pack('v',...)?
|
---|
1782 | # $es .= unpack($b,$xr->[0]);
|
---|
1783 | }
|
---|
1784 | $es = reverse $es;
|
---|
1785 | $es =~ s/^[0]+//; # strip leading zeros
|
---|
1786 | '0b' . $es; # return result prepended with 0b
|
---|
1787 | }
|
---|
1788 |
|
---|
1789 | sub _from_hex
|
---|
1790 | {
|
---|
1791 | # convert a hex number to decimal (ref to string, return ref to array)
|
---|
1792 | my ($c,$hs) = @_;
|
---|
1793 |
|
---|
1794 | my $m = _new($c, 0x10000000); # 28 bit at a time (<32 bit!)
|
---|
1795 | my $d = 7; # 7 digits at a time
|
---|
1796 | if ($] <= 5.006)
|
---|
1797 | {
|
---|
1798 | # for older Perls, play safe
|
---|
1799 | $m = [ 0x10000 ]; # 16 bit at a time (<32 bit!)
|
---|
1800 | $d = 4; # 4 digits at a time
|
---|
1801 | }
|
---|
1802 |
|
---|
1803 | my $mul = _one();
|
---|
1804 | my $x = _zero();
|
---|
1805 |
|
---|
1806 | my $len = int( (length($hs)-2)/$d ); # $d digit parts, w/o the '0x'
|
---|
1807 | my $val; my $i = -$d;
|
---|
1808 | while ($len >= 0)
|
---|
1809 | {
|
---|
1810 | $val = substr($hs,$i,$d); # get hex digits
|
---|
1811 | $val =~ s/^[+-]?0x// if $len == 0; # for last part only because
|
---|
1812 | $val = hex($val); # hex does not like wrong chars
|
---|
1813 | $i -= $d; $len --;
|
---|
1814 | my $adder = [ $val ];
|
---|
1815 | # if the resulting number was to big to fit into one element, create a
|
---|
1816 | # two-element version (bug found by Mark Lakata - Thanx!)
|
---|
1817 | if (CORE::length($val) > $BASE_LEN)
|
---|
1818 | {
|
---|
1819 | $adder = _new($c,$val);
|
---|
1820 | }
|
---|
1821 | _add ($c, $x, _mul ($c, $adder, $mul ) ) if $val != 0;
|
---|
1822 | _mul ($c, $mul, $m ) if $len >= 0; # skip last mul
|
---|
1823 | }
|
---|
1824 | $x;
|
---|
1825 | }
|
---|
1826 |
|
---|
1827 | sub _from_bin
|
---|
1828 | {
|
---|
1829 | # convert a hex number to decimal (ref to string, return ref to array)
|
---|
1830 | my ($c,$bs) = @_;
|
---|
1831 |
|
---|
1832 | # instead of converting X (8) bit at a time, it is faster to "convert" the
|
---|
1833 | # number to hex, and then call _from_hex.
|
---|
1834 |
|
---|
1835 | my $hs = $bs;
|
---|
1836 | $hs =~ s/^[+-]?0b//; # remove sign and 0b
|
---|
1837 | my $l = length($hs); # bits
|
---|
1838 | $hs = '0' x (8-($l % 8)) . $hs if ($l % 8) != 0; # padd left side w/ 0
|
---|
1839 | my $h = '0x' . unpack('H*', pack ('B*', $hs)); # repack as hex
|
---|
1840 |
|
---|
1841 | $c->_from_hex($h);
|
---|
1842 | }
|
---|
1843 |
|
---|
1844 | ##############################################################################
|
---|
1845 | # special modulus functions
|
---|
1846 |
|
---|
1847 | sub _modinv
|
---|
1848 | {
|
---|
1849 | # modular inverse
|
---|
1850 | my ($c,$x,$y) = @_;
|
---|
1851 |
|
---|
1852 | my $u = _zero($c); my $u1 = _one($c);
|
---|
1853 | my $a = _copy($c,$y); my $b = _copy($c,$x);
|
---|
1854 |
|
---|
1855 | # Euclid's Algorithm for bgcd(), only that we calc bgcd() ($a) and the
|
---|
1856 | # result ($u) at the same time. See comments in BigInt for why this works.
|
---|
1857 | my $q;
|
---|
1858 | ($a, $q, $b) = ($b, _div($c,$a,$b)); # step 1
|
---|
1859 | my $sign = 1;
|
---|
1860 | while (!_is_zero($c,$b))
|
---|
1861 | {
|
---|
1862 | my $t = _add($c, # step 2:
|
---|
1863 | _mul($c,_copy($c,$u1), $q) , # t = u1 * q
|
---|
1864 | $u ); # + u
|
---|
1865 | $u = $u1; # u = u1, u1 = t
|
---|
1866 | $u1 = $t;
|
---|
1867 | $sign = -$sign;
|
---|
1868 | ($a, $q, $b) = ($b, _div($c,$a,$b)); # step 1
|
---|
1869 | }
|
---|
1870 |
|
---|
1871 | # if the gcd is not 1, then return NaN
|
---|
1872 | return (undef,undef) unless _is_one($c,$a);
|
---|
1873 |
|
---|
1874 | ($u1, $sign == 1 ? '+' : '-');
|
---|
1875 | }
|
---|
1876 |
|
---|
1877 | sub _modpow
|
---|
1878 | {
|
---|
1879 | # modulus of power ($x ** $y) % $z
|
---|
1880 | my ($c,$num,$exp,$mod) = @_;
|
---|
1881 |
|
---|
1882 | # in the trivial case,
|
---|
1883 | if (_is_one($c,$mod))
|
---|
1884 | {
|
---|
1885 | splice @$num,0,1; $num->[0] = 0;
|
---|
1886 | return $num;
|
---|
1887 | }
|
---|
1888 | if ((scalar @$num == 1) && (($num->[0] == 0) || ($num->[0] == 1)))
|
---|
1889 | {
|
---|
1890 | $num->[0] = 1;
|
---|
1891 | return $num;
|
---|
1892 | }
|
---|
1893 |
|
---|
1894 | # $num = _mod($c,$num,$mod); # this does not make it faster
|
---|
1895 |
|
---|
1896 | my $acc = _copy($c,$num); my $t = _one();
|
---|
1897 |
|
---|
1898 | my $expbin = _as_bin($c,$exp); $expbin =~ s/^0b//;
|
---|
1899 | my $len = length($expbin);
|
---|
1900 | while (--$len >= 0)
|
---|
1901 | {
|
---|
1902 | if ( substr($expbin,$len,1) eq '1') # is_odd
|
---|
1903 | {
|
---|
1904 | _mul($c,$t,$acc);
|
---|
1905 | $t = _mod($c,$t,$mod);
|
---|
1906 | }
|
---|
1907 | _mul($c,$acc,$acc);
|
---|
1908 | $acc = _mod($c,$acc,$mod);
|
---|
1909 | }
|
---|
1910 | @$num = @$t;
|
---|
1911 | $num;
|
---|
1912 | }
|
---|
1913 |
|
---|
1914 | sub _gcd
|
---|
1915 | {
|
---|
1916 | # greatest common divisor
|
---|
1917 | my ($c,$x,$y) = @_;
|
---|
1918 |
|
---|
1919 | while ( (scalar @$y != 1) || ($y->[0] != 0) ) # while ($y != 0)
|
---|
1920 | {
|
---|
1921 | my $t = _copy($c,$y);
|
---|
1922 | $y = _mod($c, $x, $y);
|
---|
1923 | $x = $t;
|
---|
1924 | }
|
---|
1925 | $x;
|
---|
1926 | }
|
---|
1927 |
|
---|
1928 | ##############################################################################
|
---|
1929 | ##############################################################################
|
---|
1930 |
|
---|
1931 | 1;
|
---|
1932 | __END__
|
---|
1933 |
|
---|
1934 | =head1 NAME
|
---|
1935 |
|
---|
1936 | Math::BigInt::Calc - Pure Perl module to support Math::BigInt
|
---|
1937 |
|
---|
1938 | =head1 SYNOPSIS
|
---|
1939 |
|
---|
1940 | Provides support for big integer calculations. Not intended to be used by other
|
---|
1941 | modules. Other modules which sport the same functions can also be used to support
|
---|
1942 | Math::BigInt, like Math::BigInt::GMP or Math::BigInt::Pari.
|
---|
1943 |
|
---|
1944 | =head1 DESCRIPTION
|
---|
1945 |
|
---|
1946 | In order to allow for multiple big integer libraries, Math::BigInt was
|
---|
1947 | rewritten to use library modules for core math routines. Any module which
|
---|
1948 | follows the same API as this can be used instead by using the following:
|
---|
1949 |
|
---|
1950 | use Math::BigInt lib => 'libname';
|
---|
1951 |
|
---|
1952 | 'libname' is either the long name ('Math::BigInt::Pari'), or only the short
|
---|
1953 | version like 'Pari'.
|
---|
1954 |
|
---|
1955 | =head1 STORAGE
|
---|
1956 |
|
---|
1957 | =head1 METHODS
|
---|
1958 |
|
---|
1959 | The following functions MUST be defined in order to support the use by
|
---|
1960 | Math::BigInt v1.70 or later:
|
---|
1961 |
|
---|
1962 | api_version() return API version, minimum 1 for v1.70
|
---|
1963 | _new(string) return ref to new object from ref to decimal string
|
---|
1964 | _zero() return a new object with value 0
|
---|
1965 | _one() return a new object with value 1
|
---|
1966 | _two() return a new object with value 2
|
---|
1967 | _ten() return a new object with value 10
|
---|
1968 |
|
---|
1969 | _str(obj) return ref to a string representing the object
|
---|
1970 | _num(obj) returns a Perl integer/floating point number
|
---|
1971 | NOTE: because of Perl numeric notation defaults,
|
---|
1972 | the _num'ified obj may lose accuracy due to
|
---|
1973 | machine-dependend floating point size limitations
|
---|
1974 |
|
---|
1975 | _add(obj,obj) Simple addition of two objects
|
---|
1976 | _mul(obj,obj) Multiplication of two objects
|
---|
1977 | _div(obj,obj) Division of the 1st object by the 2nd
|
---|
1978 | In list context, returns (result,remainder).
|
---|
1979 | NOTE: this is integer math, so no
|
---|
1980 | fractional part will be returned.
|
---|
1981 | The second operand will be not be 0, so no need to
|
---|
1982 | check for that.
|
---|
1983 | _sub(obj,obj) Simple subtraction of 1 object from another
|
---|
1984 | a third, optional parameter indicates that the params
|
---|
1985 | are swapped. In this case, the first param needs to
|
---|
1986 | be preserved, while you can destroy the second.
|
---|
1987 | sub (x,y,1) => return x - y and keep x intact!
|
---|
1988 | _dec(obj) decrement object by one (input is garant. to be > 0)
|
---|
1989 | _inc(obj) increment object by one
|
---|
1990 |
|
---|
1991 |
|
---|
1992 | _acmp(obj,obj) <=> operator for objects (return -1, 0 or 1)
|
---|
1993 |
|
---|
1994 | _len(obj) returns count of the decimal digits of the object
|
---|
1995 | _digit(obj,n) returns the n'th decimal digit of object
|
---|
1996 |
|
---|
1997 | _is_one(obj) return true if argument is 1
|
---|
1998 | _is_two(obj) return true if argument is 2
|
---|
1999 | _is_ten(obj) return true if argument is 10
|
---|
2000 | _is_zero(obj) return true if argument is 0
|
---|
2001 | _is_even(obj) return true if argument is even (0,2,4,6..)
|
---|
2002 | _is_odd(obj) return true if argument is odd (1,3,5,7..)
|
---|
2003 |
|
---|
2004 | _copy return a ref to a true copy of the object
|
---|
2005 |
|
---|
2006 | _check(obj) check whether internal representation is still intact
|
---|
2007 | return 0 for ok, otherwise error message as string
|
---|
2008 |
|
---|
2009 | _from_hex(str) return ref to new object from ref to hexadecimal string
|
---|
2010 | _from_bin(str) return ref to new object from ref to binary string
|
---|
2011 |
|
---|
2012 | _as_hex(str) return string containing the value as
|
---|
2013 | unsigned hex string, with the '0x' prepended.
|
---|
2014 | Leading zeros must be stripped.
|
---|
2015 | _as_bin(str) Like as_hex, only as binary string containing only
|
---|
2016 | zeros and ones. Leading zeros must be stripped and a
|
---|
2017 | '0b' must be prepended.
|
---|
2018 |
|
---|
2019 | _rsft(obj,N,B) shift object in base B by N 'digits' right
|
---|
2020 | _lsft(obj,N,B) shift object in base B by N 'digits' left
|
---|
2021 |
|
---|
2022 | _xor(obj1,obj2) XOR (bit-wise) object 1 with object 2
|
---|
2023 | Note: XOR, AND and OR pad with zeros if size mismatches
|
---|
2024 | _and(obj1,obj2) AND (bit-wise) object 1 with object 2
|
---|
2025 | _or(obj1,obj2) OR (bit-wise) object 1 with object 2
|
---|
2026 |
|
---|
2027 | _mod(obj,obj) Return remainder of div of the 1st by the 2nd object
|
---|
2028 | _sqrt(obj) return the square root of object (truncated to int)
|
---|
2029 | _root(obj) return the n'th (n >= 3) root of obj (truncated to int)
|
---|
2030 | _fac(obj) return factorial of object 1 (1*2*3*4..)
|
---|
2031 | _pow(obj,obj) return object 1 to the power of object 2
|
---|
2032 | return undef for NaN
|
---|
2033 | _zeros(obj) return number of trailing decimal zeros
|
---|
2034 | _modinv return inverse modulus
|
---|
2035 | _modpow return modulus of power ($x ** $y) % $z
|
---|
2036 | _log_int(X,N) calculate integer log() of X in base N
|
---|
2037 | X >= 0, N >= 0 (return undef for NaN)
|
---|
2038 | returns (RESULT, EXACT) where EXACT is:
|
---|
2039 | 1 : result is exactly RESULT
|
---|
2040 | 0 : result was truncated to RESULT
|
---|
2041 | undef : unknown whether result is exactly RESULT
|
---|
2042 | _gcd(obj,obj) return Greatest Common Divisor of two objects
|
---|
2043 |
|
---|
2044 | The following functions are optional, and can be defined if the underlying lib
|
---|
2045 | has a fast way to do them. If undefined, Math::BigInt will use pure Perl (hence
|
---|
2046 | slow) fallback routines to emulate these:
|
---|
2047 |
|
---|
2048 | _signed_or
|
---|
2049 | _signed_and
|
---|
2050 | _signed_xor
|
---|
2051 |
|
---|
2052 |
|
---|
2053 | Input strings come in as unsigned but with prefix (i.e. as '123', '0xabc'
|
---|
2054 | or '0b1101').
|
---|
2055 |
|
---|
2056 | So the library needs only to deal with unsigned big integers. Testing of input
|
---|
2057 | parameter validity is done by the caller, so you need not worry about
|
---|
2058 | underflow (f.i. in C<_sub()>, C<_dec()>) nor about division by zero or similar
|
---|
2059 | cases.
|
---|
2060 |
|
---|
2061 | The first parameter can be modified, that includes the possibility that you
|
---|
2062 | return a reference to a completely different object instead. Although keeping
|
---|
2063 | the reference and just changing it's contents is prefered over creating and
|
---|
2064 | returning a different reference.
|
---|
2065 |
|
---|
2066 | Return values are always references to objects, strings, or true/false for
|
---|
2067 | comparisation routines.
|
---|
2068 |
|
---|
2069 | =head1 WRAP YOUR OWN
|
---|
2070 |
|
---|
2071 | If you want to port your own favourite c-lib for big numbers to the
|
---|
2072 | Math::BigInt interface, you can take any of the already existing modules as
|
---|
2073 | a rough guideline. You should really wrap up the latest BigInt and BigFloat
|
---|
2074 | testsuites with your module, and replace in them any of the following:
|
---|
2075 |
|
---|
2076 | use Math::BigInt;
|
---|
2077 |
|
---|
2078 | by this:
|
---|
2079 |
|
---|
2080 | use Math::BigInt lib => 'yourlib';
|
---|
2081 |
|
---|
2082 | This way you ensure that your library really works 100% within Math::BigInt.
|
---|
2083 |
|
---|
2084 | =head1 LICENSE
|
---|
2085 |
|
---|
2086 | This program is free software; you may redistribute it and/or modify it under
|
---|
2087 | the same terms as Perl itself.
|
---|
2088 |
|
---|
2089 | =head1 AUTHORS
|
---|
2090 |
|
---|
2091 | Original math code by Mark Biggar, rewritten by Tels L<http://bloodgate.com/>
|
---|
2092 | in late 2000.
|
---|
2093 | Seperated from BigInt and shaped API with the help of John Peacock.
|
---|
2094 |
|
---|
2095 | Fixed, speed-up, streamlined and enhanced by Tels 2001 - 2005.
|
---|
2096 |
|
---|
2097 | =head1 SEE ALSO
|
---|
2098 |
|
---|
2099 | L<Math::BigInt>, L<Math::BigFloat>, L<Math::BigInt::BitVect>,
|
---|
2100 | L<Math::BigInt::GMP>, L<Math::BigInt::FastCalc> and L<Math::BigInt::Pari>.
|
---|
2101 |
|
---|
2102 | =cut
|
---|