| /* |
| * Copyright 2013 The Emscripten Authors. All rights reserved. |
| * Emscripten is available under two separate licenses, the MIT license and the |
| * University of Illinois/NCSA Open Source License. Both these licenses can be |
| * found in the LICENSE file. |
| */ |
| |
| /* |
| * Licensed to the Apache Software Foundation (ASF) under one or more |
| * contributor license agreements. See the NOTICE file distributed with |
| * this work for additional information regarding copyright ownership. |
| * The ASF licenses this file to You under the Apache License, Version 2.0 |
| * (the "License"); you may not use this file except in compliance with |
| * the License. You may obtain a copy of the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, software |
| * distributed under the License is distributed on an "AS IS" BASIS, |
| * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| * See the License for the specific language governing permissions and |
| * limitations under the License. |
| * |
| * cbigint.c has been adapted for xmlvm |
| */ |
| #include "xmlvm-number.h" |
| |
| |
| U_32 |
| simpleMultiplyHighPrecision (U_64 * arg1, IDATA length, U_64 arg2) |
| { |
| /* assumes arg2 only holds 32 bits of information */ |
| U_64 product; |
| IDATA index; |
| |
| index = 0; |
| product = 0; |
| |
| do |
| { |
| product = |
| HIGH_IN_U64 (product) + arg2 * LOW_U32_FROM_PTR (arg1 + index); |
| LOW_U32_FROM_PTR (arg1 + index) = LOW_U32_FROM_VAR (product); |
| product = |
| HIGH_IN_U64 (product) + arg2 * HIGH_U32_FROM_PTR (arg1 + index); |
| HIGH_U32_FROM_PTR (arg1 + index) = LOW_U32_FROM_VAR (product); |
| } |
| while (++index < length); |
| |
| return HIGH_U32_FROM_VAR (product); |
| } |
| |
| void simpleShiftLeftHighPrecision (U_64 * arg1, IDATA length, IDATA arg2) |
| { |
| /* assumes length > 0 */ |
| IDATA index, offset; |
| if (arg2 >= 64) |
| { |
| offset = arg2 >> 6; |
| index = length; |
| |
| while (--index - offset >= 0) |
| arg1[index] = arg1[index - offset]; |
| do |
| { |
| arg1[index] = 0; |
| } |
| while (--index >= 0); |
| |
| arg2 &= 0x3F; |
| } |
| |
| if (arg2 == 0) |
| return; |
| while (--length > 0) |
| { |
| arg1[length] = arg1[length] << arg2 | arg1[length - 1] >> (64 - arg2); |
| } |
| *arg1 <<= arg2; |
| } |
| |
| |
| U_64 simpleMultiplyHighPrecision64 (U_64 * arg1, IDATA length, U_64 arg2) |
| { |
| U_64 intermediate, *pArg1, carry1, carry2, prod1, prod2, sum; |
| IDATA index; |
| U_32 buf32; |
| |
| index = 0; |
| intermediate = 0; |
| pArg1 = arg1 + index; |
| carry1 = carry2 = 0; |
| |
| do |
| { |
| if ((*pArg1 != 0) || (intermediate != 0)) |
| { |
| prod1 = |
| (U_64) LOW_U32_FROM_VAR (arg2) * (U_64) LOW_U32_FROM_PTR (pArg1); |
| sum = intermediate + prod1; |
| if ((sum < prod1) || (sum < intermediate)) |
| { |
| carry1 = 1; |
| } |
| else |
| { |
| carry1 = 0; |
| } |
| prod1 = |
| (U_64) LOW_U32_FROM_VAR (arg2) * (U_64) HIGH_U32_FROM_PTR (pArg1); |
| prod2 = |
| (U_64) HIGH_U32_FROM_VAR (arg2) * (U_64) LOW_U32_FROM_PTR (pArg1); |
| intermediate = carry2 + HIGH_IN_U64 (sum) + prod1 + prod2; |
| if ((intermediate < prod1) || (intermediate < prod2)) |
| { |
| carry2 = 1; |
| } |
| else |
| { |
| carry2 = 0; |
| } |
| LOW_U32_FROM_PTR (pArg1) = LOW_U32_FROM_VAR (sum); |
| buf32 = HIGH_U32_FROM_PTR (pArg1); |
| HIGH_U32_FROM_PTR (pArg1) = LOW_U32_FROM_VAR (intermediate); |
| intermediate = carry1 + HIGH_IN_U64 (intermediate) |
| + (U_64) HIGH_U32_FROM_VAR (arg2) * (U_64) buf32; |
| } |
| pArg1++; |
| } |
| while (++index < length); |
| return intermediate; |
| } |
| |
| U_32 simpleAppendDecimalDigitHighPrecision (U_64 * arg1, IDATA length, U_64 digit) |
| { |
| /* assumes digit is less than 32 bits */ |
| U_64 arg; |
| IDATA index = 0; |
| |
| digit <<= 32; |
| do |
| { |
| arg = LOW_IN_U64 (arg1[index]); |
| digit = HIGH_IN_U64 (digit) + TIMES_TEN (arg); |
| LOW_U32_FROM_PTR (arg1 + index) = LOW_U32_FROM_VAR (digit); |
| |
| arg = HIGH_IN_U64 (arg1[index]); |
| digit = HIGH_IN_U64 (digit) + TIMES_TEN (arg); |
| HIGH_U32_FROM_PTR (arg1 + index) = LOW_U32_FROM_VAR (digit); |
| } |
| while (++index < length); |
| |
| return HIGH_U32_FROM_VAR (digit); |
| } |
| |
| IDATA timesTenToTheEHighPrecision (U_64 * result, IDATA length, JAVA_INT e) |
| { |
| /* assumes result can hold value */ |
| U_64 overflow; |
| int exp10 = e; |
| |
| if (e == 0) |
| return length; |
| |
| while (exp10 >= 19) |
| { |
| overflow = simpleMultiplyHighPrecision64 (result, length, TEN_E19); |
| if (overflow) |
| result[length++] = overflow; |
| exp10 -= 19; |
| } |
| while (exp10 >= 9) |
| { |
| overflow = simpleMultiplyHighPrecision (result, length, TEN_E9); |
| if (overflow) |
| result[length++] = overflow; |
| exp10 -= 9; |
| } |
| if (exp10 == 0) |
| return length; |
| else if (exp10 == 1) |
| { |
| overflow = simpleAppendDecimalDigitHighPrecision (result, length, 0); |
| if (overflow) |
| result[length++] = overflow; |
| } |
| else if (exp10 == 2) |
| { |
| overflow = simpleAppendDecimalDigitHighPrecision (result, length, 0); |
| if (overflow) |
| result[length++] = overflow; |
| overflow = simpleAppendDecimalDigitHighPrecision (result, length, 0); |
| if (overflow) |
| result[length++] = overflow; |
| } |
| else if (exp10 == 3) |
| { |
| overflow = simpleMultiplyHighPrecision (result, length, TEN_E3); |
| if (overflow) |
| result[length++] = overflow; |
| } |
| else if (exp10 == 4) |
| { |
| overflow = simpleMultiplyHighPrecision (result, length, TEN_E4); |
| if (overflow) |
| result[length++] = overflow; |
| } |
| else if (exp10 == 5) |
| { |
| overflow = simpleMultiplyHighPrecision (result, length, TEN_E5); |
| if (overflow) |
| result[length++] = overflow; |
| } |
| else if (exp10 == 6) |
| { |
| overflow = simpleMultiplyHighPrecision (result, length, TEN_E6); |
| if (overflow) |
| result[length++] = overflow; |
| } |
| else if (exp10 == 7) |
| { |
| overflow = simpleMultiplyHighPrecision (result, length, TEN_E7); |
| if (overflow) |
| result[length++] = overflow; |
| } |
| else if (exp10 == 8) |
| { |
| overflow = simpleMultiplyHighPrecision (result, length, TEN_E8); |
| if (overflow) |
| result[length++] = overflow; |
| } |
| return length; |
| } |
| |
| IDATA addHighPrecision (U_64 * arg1, IDATA length1, U_64 * arg2, IDATA length2) |
| { |
| |
| U_64 temp1, temp2, temp3; /* temporary variables to help the SH-4, and gcc */ |
| U_64 carry; |
| IDATA index; |
| |
| if (length1 == 0 || length2 == 0) |
| { |
| return 0; |
| } |
| else if (length1 < length2) |
| { |
| length2 = length1; |
| } |
| |
| carry = 0; |
| index = 0; |
| do |
| { |
| temp1 = arg1[index]; |
| temp2 = arg2[index]; |
| temp3 = temp1 + temp2; |
| arg1[index] = temp3 + carry; |
| if (arg2[index] < arg1[index]) |
| carry = 0; |
| else if (arg2[index] != arg1[index]) |
| carry = 1; |
| } |
| while (++index < length2); |
| if (!carry) |
| return 0; |
| else if (index == length1) |
| return 1; |
| |
| while (++arg1[index] == 0 && ++index < length1); |
| |
| return (IDATA) index == length1; |
| } |
| |
| IDATA |
| compareHighPrecision (U_64 * arg1, IDATA length1, U_64 * arg2, IDATA length2) |
| { |
| while (--length1 >= 0 && arg1[length1] == 0); |
| while (--length2 >= 0 && arg2[length2] == 0); |
| |
| if (length1 > length2) |
| return 1; |
| else if (length1 < length2) |
| return -1; |
| else if (length1 > -1) |
| { |
| do |
| { |
| if (arg1[length1] > arg2[length1]) |
| return 1; |
| else if (arg1[length1] < arg2[length1]) |
| return -1; |
| } |
| while (--length1 >= 0); |
| } |
| |
| return 0; |
| } |
| |
| IDATA |
| simpleAddHighPrecision (U_64 * arg1, IDATA length, U_64 arg2) |
| { |
| /* assumes length > 0 */ |
| IDATA index = 1; |
| |
| *arg1 += arg2; |
| if (arg2 <= *arg1) |
| return 0; |
| else if (length == 1) |
| return 1; |
| |
| while (++arg1[index] == 0 && ++index < length); |
| |
| return (IDATA) index == length; |
| } |
| |
| void |
| subtractHighPrecision (U_64 * arg1, IDATA length1, U_64 * arg2, IDATA length2) |
| { |
| /* assumes arg1 > arg2 */ |
| IDATA index; |
| for (index = 0; index < length1; ++index) |
| arg1[index] = ~arg1[index]; |
| simpleAddHighPrecision (arg1, length1, 1); |
| |
| while (length2 > 0 && arg2[length2 - 1] == 0) |
| --length2; |
| |
| addHighPrecision (arg1, length1, arg2, length2); |
| |
| for (index = 0; index < length1; ++index) |
| arg1[index] = ~arg1[index]; |
| simpleAddHighPrecision (arg1, length1, 1); |
| } |