10 if (scalar @_ != 1) { return "NaN"; }
15 my ($sign, $hex) = (shift =~ /^([+\-]?)(.*)$/);
16 $hex = "0x".$hex if $hex !~ /^0x/;
21 @_ = __multiplier(@_);
22 while (scalar @_ > 1 && $_[1] =~ /^[\+\-]$/) {
23 my $operand1 = Math::BigInt->from_hex(__canonhex(shift));
25 @_ = __multiplier(@_);
26 my $operand2 = Math::BigInt->from_hex(__canonhex(shift));
27 if ($operator eq "+") {
28 $operand1->badd($operand2);
29 } elsif ($operator eq "-") {
30 $operand1->bsub($operand2);
32 die "SOMETHING WENT AWFULLY WRONG";
34 unshift @_, $operand1->as_hex();
41 while (scalar @_ > 1 && $_[1] =~ /^[\*\/%]$/) {
42 my $operand1 = Math::BigInt->from_hex(__canonhex(shift));
45 my $operand2 = Math::BigInt->from_hex(__canonhex(shift));
46 if ($operator eq "*") {
47 $operand1->bmul($operand2);
48 } elsif ($operator eq "/") {
49 # Math::BigInt->bdiv() is documented to do floored division,
50 # i.e. 1 / -4 = -1, while bc and OpenSSL BN_div do truncated
51 # division, i.e. 1 / -4 = 0. We need to make the operation
52 # work like OpenSSL's BN_div to be able to verify.
53 my $neg = ($operand1->is_neg()
54 ? !$operand2->is_neg() : $operand2->is_neg());
57 $operand1->bdiv($operand2);
58 if ($neg) { $operand1->bneg(); }
59 } elsif ($operator eq "%") {
60 # Here's a bit of a quirk...
61 # With OpenSSL's BN, as well as bc, the result of -10 % 3 is -1
62 # while Math::BigInt, the result is 2.
63 # The latter is mathematically more correct, but...
64 my $o1isneg = $operand1->is_neg();
66 # Math::BigInt does something different with a negative modulus,
67 # while OpenSSL's BN and bc treat it like a positive number...
69 $operand1->bmod($operand2);
70 if ($o1isneg) { $operand1->bneg(); }
72 die "SOMETHING WENT AWFULLY WRONG";
74 unshift @_, $operand1->as_hex();
81 while (scalar @_ > 1 && $_[1] eq "^") {
82 my $operand1 = Math::BigInt->from_hex(__canonhex(shift));
85 my $operand2 = Math::BigInt->from_hex(__canonhex(shift));
86 $operand1->bpow($operand2);
87 unshift @_, $operand1->as_hex();
92 # returns array ( $result, @remaining )
94 if (scalar @_ > 0 && $_[0] eq "(") {
96 my @result = __adder(@_);
97 if (scalar @_ == 0 || $_[0] ne ")") {