xref: /onnv-gate/usr/src/cmd/perl/5.8.4/distrib/lib/Math/BigInt/CalcEmu.pm (revision 0:68f95e015346)
1package Math::BigInt::CalcEmu;
2
3use 5.005;
4use strict;
5# use warnings;	# dont use warnings for older Perls
6use vars qw/$VERSION/;
7
8$VERSION = '0.04';
9
10package Math::BigInt;
11
12# See SYNOPSIS below.
13
14my $CALC_EMU;
15
16BEGIN
17  {
18  $CALC_EMU = Math::BigInt->config()->{'lib'};
19  }
20
21sub __emu_band
22  {
23  my ($self,$x,$y,$sx,$sy,@r) = @_;
24
25  return $x->bzero(@r) if $y->is_zero() || $x->is_zero();
26
27  my $sign = 0;					# sign of result
28  $sign = 1 if $sx == -1 && $sy == -1;
29
30  my ($bx,$by);
31
32  if ($sx == -1)				# if x is negative
33    {
34    # two's complement: inc and flip all "bits" in $bx
35    $bx = $x->binc()->as_hex();			# -1 => 0, -2 => 1, -3 => 2 etc
36    $bx =~ s/-?0x//;
37    $bx =~ tr/0123456789abcdef/\x0f\x0e\x0d\x0c\x0b\x0a\x09\x08\x07\x06\x05\x04\x03\x02\x01\x00/;
38    }
39  else
40    {
41    $bx = $x->as_hex();				# get binary representation
42    $bx =~ s/-?0x//;
43    $bx =~ tr/fedcba9876543210/\x0f\x0e\x0d\x0c\x0b\x0a\x09\x08\x07\x06\x05\x04\x03\x02\x01\x00/;
44    }
45  if ($sy == -1)				# if y is negative
46    {
47    # two's complement: inc and flip all "bits" in $by
48    $by = $y->copy()->binc()->as_hex();		# -1 => 0, -2 => 1, -3 => 2 etc
49    $by =~ s/-?0x//;
50    $by =~ tr/0123456789abcdef/\x0f\x0e\x0d\x0c\x0b\x0a\x09\x08\x07\x06\x05\x04\x03\x02\x01\x00/;
51    }
52  else
53    {
54    $by = $y->as_hex();				# get binary representation
55    $by =~ s/-?0x//;
56    $by =~ tr/fedcba9876543210/\x0f\x0e\x0d\x0c\x0b\x0a\x09\x08\x07\x06\x05\x04\x03\x02\x01\x00/;
57    }
58  # now we have bit-strings from X and Y, reverse them for padding
59  $bx = reverse $bx;
60  $by = reverse $by;
61
62  # padd the shorter string
63  my $xx = "\x00"; $xx = "\x0f" if $sx == -1;
64  my $yy = "\x00"; $yy = "\x0f" if $sy == -1;
65  my $diff = CORE::length($bx) - CORE::length($by);
66  if ($diff > 0)
67    {
68    # if $yy eq "\x00", we can cut $bx, otherwise we need to padd $by
69    $by .= $yy x $diff;
70    }
71  elsif ($diff < 0)
72    {
73    # if $xx eq "\x00", we can cut $by, otherwise we need to padd $bx
74    $bx .= $xx x abs($diff);
75    }
76
77  # and the strings together
78  my $r = $bx & $by;
79
80  # and reverse the result again
81  $bx = reverse $r;
82
83  # One of $x or $y was negative, so need to flip bits in the result.
84  # In both cases (one or two of them negative, or both positive) we need
85  # to get the characters back.
86  if ($sign == 1)
87    {
88    $bx =~ tr/\x0f\x0e\x0d\x0c\x0b\x0a\x09\x08\x07\x06\x05\x04\x03\x02\x01\x00/0123456789abcdef/;
89    }
90  else
91    {
92    $bx =~ tr/\x0f\x0e\x0d\x0c\x0b\x0a\x09\x08\x07\x06\x05\x04\x03\x02\x01\x00/fedcba9876543210/;
93    }
94
95  # leading zeros will be stripped by _from_hex()
96  $bx = '0x' . $bx;
97  $x->{value} = $CALC_EMU->_from_hex( $bx );
98
99  # calculate sign of result
100  $x->{sign} = '+';
101  $x->{sign} = '-' if $sign == 1 && !$x->is_zero();
102
103  $x->bdec() if $sign == 1;
104
105  $x->round(@r);
106  }
107
108sub __emu_bior
109  {
110  my ($self,$x,$y,$sx,$sy,@r) = @_;
111
112  return $x->round(@r) if $y->is_zero();
113
114  my $sign = 0;					# sign of result
115  $sign = 1 if ($sx == -1) || ($sy == -1);
116
117  my ($bx,$by);
118
119  if ($sx == -1)				# if x is negative
120    {
121    # two's complement: inc and flip all "bits" in $bx
122    $bx = $x->binc()->as_hex();			# -1 => 0, -2 => 1, -3 => 2 etc
123    $bx =~ s/-?0x//;
124    $bx =~ tr/0123456789abcdef/\x0f\x0e\x0d\x0c\x0b\x0a\x09\x08\x07\x06\x05\x04\x03\x02\x01\x00/;
125    }
126  else
127    {
128    $bx = $x->as_hex();				# get binary representation
129    $bx =~ s/-?0x//;
130    $bx =~ tr/fedcba9876543210/\x0f\x0e\x0d\x0c\x0b\x0a\x09\x08\x07\x06\x05\x04\x03\x02\x01\x00/;
131    }
132  if ($sy == -1)				# if y is negative
133    {
134    # two's complement: inc and flip all "bits" in $by
135    $by = $y->copy()->binc()->as_hex();		# -1 => 0, -2 => 1, -3 => 2 etc
136    $by =~ s/-?0x//;
137    $by =~ tr/0123456789abcdef/\x0f\x0e\x0d\x0c\x0b\x0a\x09\x08\x07\x06\x05\x04\x03\x02\x01\x00/;
138    }
139  else
140    {
141    $by = $y->as_hex();				# get binary representation
142    $by =~ s/-?0x//;
143    $by =~ tr/fedcba9876543210/\x0f\x0e\x0d\x0c\x0b\x0a\x09\x08\x07\x06\x05\x04\x03\x02\x01\x00/;
144    }
145  # now we have bit-strings from X and Y, reverse them for padding
146  $bx = reverse $bx;
147  $by = reverse $by;
148
149  # padd the shorter string
150  my $xx = "\x00"; $xx = "\x0f" if $sx == -1;
151  my $yy = "\x00"; $yy = "\x0f" if $sy == -1;
152  my $diff = CORE::length($bx) - CORE::length($by);
153  if ($diff > 0)
154    {
155    $by .= $yy x $diff;
156    }
157  elsif ($diff < 0)
158    {
159    $bx .= $xx x abs($diff);
160    }
161
162  # or the strings together
163  my $r = $bx | $by;
164
165  # and reverse the result again
166  $bx = reverse $r;
167
168  # one of $x or $y was negative, so need to flip bits in the result
169  # in both cases (one or two of them negative, or both positive) we need
170  # to get the characters back.
171  if ($sign == 1)
172    {
173    $bx =~ tr/\x0f\x0e\x0d\x0c\x0b\x0a\x09\x08\x07\x06\x05\x04\x03\x02\x01\x00/0123456789abcdef/;
174    }
175  else
176    {
177    $bx =~ tr/\x0f\x0e\x0d\x0c\x0b\x0a\x09\x08\x07\x06\x05\x04\x03\x02\x01\x00/fedcba9876543210/;
178    }
179
180  # leading zeros will be stripped by _from_hex()
181  $bx = '0x' . $bx;
182  $x->{value} = $CALC_EMU->_from_hex( $bx );
183
184  # calculate sign of result
185  $x->{sign} = '+';
186  $x->{sign} = '-' if $sign == 1 && !$x->is_zero();
187
188  # if one of X or Y was negative, we need to decrement result
189  $x->bdec() if $sign == 1;
190
191  $x->round(@r);
192  }
193
194sub __emu_bxor
195  {
196  my ($self,$x,$y,$sx,$sy,@r) = @_;
197
198  return $x->round(@r) if $y->is_zero();
199
200  my $sign = 0;					# sign of result
201  $sign = 1 if $x->{sign} ne $y->{sign};
202
203  my ($bx,$by);
204
205  if ($sx == -1)				# if x is negative
206    {
207    # two's complement: inc and flip all "bits" in $bx
208    $bx = $x->binc()->as_hex();			# -1 => 0, -2 => 1, -3 => 2 etc
209    $bx =~ s/-?0x//;
210    $bx =~ tr/0123456789abcdef/\x0f\x0e\x0d\x0c\x0b\x0a\x09\x08\x07\x06\x05\x04\x03\x02\x01\x00/;
211    }
212  else
213    {
214    $bx = $x->as_hex();				# get binary representation
215    $bx =~ s/-?0x//;
216    $bx =~ tr/fedcba9876543210/\x0f\x0e\x0d\x0c\x0b\x0a\x09\x08\x07\x06\x05\x04\x03\x02\x01\x00/;
217    }
218  if ($sy == -1)				# if y is negative
219    {
220    # two's complement: inc and flip all "bits" in $by
221    $by = $y->copy()->binc()->as_hex();		# -1 => 0, -2 => 1, -3 => 2 etc
222    $by =~ s/-?0x//;
223    $by =~ tr/0123456789abcdef/\x0f\x0e\x0d\x0c\x0b\x0a\x09\x08\x07\x06\x05\x04\x03\x02\x01\x00/;
224    }
225  else
226    {
227    $by = $y->as_hex();				# get binary representation
228    $by =~ s/-?0x//;
229    $by =~ tr/fedcba9876543210/\x0f\x0e\x0d\x0c\x0b\x0a\x09\x08\x07\x06\x05\x04\x03\x02\x01\x00/;
230    }
231  # now we have bit-strings from X and Y, reverse them for padding
232  $bx = reverse $bx;
233  $by = reverse $by;
234
235  # padd the shorter string
236  my $xx = "\x00"; $xx = "\x0f" if $sx == -1;
237  my $yy = "\x00"; $yy = "\x0f" if $sy == -1;
238  my $diff = CORE::length($bx) - CORE::length($by);
239  if ($diff > 0)
240    {
241    $by .= $yy x $diff;
242    }
243  elsif ($diff < 0)
244    {
245    $bx .= $xx x abs($diff);
246    }
247
248  # xor the strings together
249  my $r = $bx ^ $by;
250
251  # and reverse the result again
252  $bx = reverse $r;
253
254  # one of $x or $y was negative, so need to flip bits in the result
255  # in both cases (one or two of them negative, or both positive) we need
256  # to get the characters back.
257  if ($sign == 1)
258    {
259    $bx =~ tr/\x0f\x0e\x0d\x0c\x0b\x0a\x09\x08\x07\x06\x05\x04\x03\x02\x01\x00/0123456789abcdef/;
260    }
261  else
262    {
263    $bx =~ tr/\x0f\x0e\x0d\x0c\x0b\x0a\x09\x08\x07\x06\x05\x04\x03\x02\x01\x00/fedcba9876543210/;
264    }
265
266  # leading zeros will be stripped by _from_hex()
267  $bx = '0x' . $bx;
268  $x->{value} = $CALC_EMU->_from_hex( $bx );
269
270  # calculate sign of result
271  $x->{sign} = '+';
272  $x->{sign} = '-' if $sx != $sy && !$x->is_zero();
273
274  $x->bdec() if $sign == 1;
275
276  $x->round(@r);
277  }
278
279##############################################################################
280##############################################################################
281
2821;
283__END__
284
285=head1 NAME
286
287Math::BigInt::CalcEmu - Emulate low-level math with BigInt code
288
289=head1 SYNOPSIS
290
291Contains routines that emulate low-level math functions in BigInt, e.g.
292optional routines the low-level math package does not provide on it's own.
293
294Will be loaded on demand and automatically by BigInt.
295
296Stuff here is really low-priority to optimize,
297since it is far better to implement the operation in the low-level math
298libary directly, possible even using a call to the native lib.
299
300=head1 DESCRIPTION
301
302=head1 METHODS
303
304=head1 LICENSE
305
306This program is free software; you may redistribute it and/or modify it under
307the same terms as Perl itself.
308
309=head1 AUTHORS
310
311(c) Tels http://bloodgate.com 2003, 2004 - based on BigInt code by
312Tels from 2001-2003.
313
314=head1 SEE ALSO
315
316L<Math::BigInt>, L<Math::BigFloat>, L<Math::BigInt::BitVect>,
317L<Math::BigInt::GMP> and L<Math::BigInt::Pari>.
318
319=cut
320