static int fcubes(BigInteger *pArgument) { int mod18, modulus, i, mod83, mask; int pow, exp; boolean converted = FALSE; CopyBigInt(&value, pArgument); // Compute argument mod 18. mod18 = getRemainder(pArgument, 18); if (mod18 == 4 || mod18 == 5 || mod18 == 13 || mod18 == 14) { return -1; // Applet does not work if the number is congruent to 4 or 5 (mod 9) } if (mod18 == 16) { // Change sign. converted = TRUE; BigIntNegate(&value, &value); } for (i = 0; i<(int)(sizeof(sums)/sizeof(sums[0])); i += 10) { modulus = sums[i]; if ((getRemainder(&value, modulus) + modulus)% modulus == sums[i + 1]) { break; } } if (i<(int)(sizeof(sums) / sizeof(sums[0]))) { subtractdivide(&value, sums[i + 1], modulus); // value <- (value-sums[i+1])/modulus multadd(&Base1, sums[i + 2], &value, sums[i + 3]); // Base1 <- sums[i+2]*value+sums[i+3] multadd(&Base2, sums[i + 4], &value, sums[i + 5]); // Base2 <- sums[i+4]*value+sums[i+5] multadd(&Base3, sums[i + 6], &value, sums[i + 7]); // Base3 <- sums[i+6]*value+sums[i+7] multadd(&Base4, sums[i + 8], &value, sums[i + 9]); // Base4 <- sums[i+8]*value+sums[i+9] } else if (getRemainder(&value, 54) == 2) { // If value == 2 (mod 54)... subtractdivide(&value, 2, 54); // value <- (value-2)/54 EvaluateQuadraticPoly(&Base1, &value, 29484, 2211, 43); EvaluateQuadraticPoly(&Base2, &value, -29484, -2157, -41); EvaluateQuadraticPoly(&Base3, &value, 9828, 485, 4); EvaluateQuadraticPoly(&Base4, &value, -9828, -971, -22); } else if (getRemainder(&value, 83 * 108) == 83*46) { // If value == 83*46 (mod 83*108)... subtractdivide(&value, 83*46, 83*108); // value <-(value - (83*46)) / (83*108) EvaluateQuadraticPoly(&Base1, &value, 29484, 25143, 5371); EvaluateQuadraticPoly(&Base2, &value, -29484, -25089, -5348); EvaluateQuadraticPoly(&Base3, &value, 9828, 8129, 1682); EvaluateQuadraticPoly(&Base4, &value, -9828, -8615, -1889); } else { // Perform Pell solution of Demjanenko's theorem // Using these values of P, Q, R and S, a and b will be // always one and zero (mod 6) respectively. // P <- -112488782561 = -(52*2^31+819632865) // Q <- -6578430178320 = -(3063*2^31+687764496) // R <- -1923517596 = -(0*2^31+1923517596) // S <- P // P1 <- 1 // Q1 <- 0 // R1 <- 0 // S1 <- 1 P.limbs[1].x = S.limbs[1].x = 52; P.limbs[0].x = S.limbs[0].x = 819632865; Q.limbs[1].x = 3063; Q.limbs[0].x = 687764496; R.limbs[1].x = 0; R.limbs[0].x = 1923517596; P.nbrLimbs = Q.nbrLimbs = R.nbrLimbs = S.nbrLimbs = 3; P.sign = Q.sign = R.sign = S.sign = SIGN_NEGATIVE; P1.limbs[0].x = S1.limbs[0].x = 1; Q1.limbs[0].x = R1.limbs[0].x = 0; P1.nbrLimbs = Q1.nbrLimbs = R1.nbrLimbs = S1.nbrLimbs = 1; P1.sign = Q1.sign = R1.sign = S1.sign = SIGN_POSITIVE; mod83 = getRemainder(&value, 83); pow = 71; exp = 0; while (pow != mod83) { exp++; pow = (pow * 50) % 83; } if (exp > 82 / 2) { exp = 82 - exp; Q.sign = R.sign = SIGN_POSITIVE; } // Now exp is in range 0-41. mask = 32; while (mask > 0) { // tmpP1 <- P1*P1 + Q1*R1 // tmpQ1 <- (P1+S1) * Q1 // tmpR1 <- (P1+S1) * R1 // tmpS1 <- S1*S1 + Q1*R1 // P1 <- tmpP1 // Q1 <- tmpQ1 // R1 <- tmpR1 // S1 <- tmpS1 (void)BigIntMultiply(&P1, &P1, &tmpP1); (void)BigIntMultiply(&Q1, &R1, &tmpQ1); (void)BigIntMultiply(&S1, &S1, &tmpS1); BigIntAdd(&P1, &S1, &tmpR1); BigIntAdd(&tmpP1, &tmpQ1, &P1); BigIntAdd(&tmpS1, &tmpQ1, &S1); (void)BigIntMultiply(&tmpR1, &Q1, &Q1); (void)BigIntMultiply(&tmpR1, &R1, &R1); if ((exp & mask) != 0) { // tmpP1 <- P*P1 + Q*R1 // tmpQ1 <- P*Q1 + Q*S1 // tmpR1 <- R*P1 + S*R1 // tmpS1 <- R*Q1 + S*S1 // P1 <- tmpP1 // Q1 <- tmpQ1 // R1 <- tmpR1 // S1 <- tmpS1 (void)BigIntMultiply(&P, &P1, &tmpP1); (void)BigIntMultiply(&Q, &R1, &tmpQ1); (void)BigIntMultiply(&R, &P1, &tmpR1); (void)BigIntMultiply(&S, &R1, &tmpS1); BigIntAdd(&tmpP1, &tmpQ1, &P1); BigIntAdd(&tmpR1, &tmpS1, &R1); (void)BigIntMultiply(&P, &Q1, &tmpP1); (void)BigIntMultiply(&Q, &S1, &tmpQ1); (void)BigIntMultiply(&R, &Q1, &tmpR1); (void)BigIntMultiply(&S, &S1, &tmpS1); BigIntAdd(&tmpP1, &tmpQ1, &Q1); BigIntAdd(&tmpR1, &tmpS1, &S1); } mask >>= 1; } addmult(&a, &P1, -3041, &Q1, -52); // a <- -3041*P1 - 52*Q1 addmult(&b, &R1, -3041, &S1, -52); // b <- -3041*R1 - 52*S1 addmult(&Base1, &a, 27, &b, -928); // Base1 <- 27*a - 928*b addmult(&Base2, &a, -9, &b, -602); // Base2 <- -9*a - 602*b addmult(&Base3, &a, 25, &b, -2937); // Base3 <- 25*a - 2937*b addmult(&Base4, &a, -19, &b, 2746); // Base4 <- -19*a - 2746*b // a <- (value - Base1^3 - Base2^3 - Base3^3 - Base4^3)/(18*83) getSumOfCubes(); // tmpP1 = Base1^3 + Base2^3 + Base3^3 + Base4^3 BigIntSubt(&value, &tmpP1, &a); subtractdivide(&a, 0, 18 * 83); // Divide a by 18*83. multint(&tmpP1, &a, 10); // Base1 <- Base1 + 10*a BigIntAdd(&tmpP1, &Base1, &Base1); multint(&tmpP1, &a, -19); // Base2 <- Base2 - 19*a BigIntAdd(&tmpP1, &Base2, &Base2); multint(&tmpP1, &a, -24); // Base3 <- Base3 - 24*a BigIntAdd(&tmpP1, &Base3, &Base3); multint(&tmpP1, &a, 27); // Base4 <- Base4 + 27*a BigIntAdd(&tmpP1, &Base4, &Base4); } if (converted != 0) { BigIntNegate(&Base1, &Base1); BigIntNegate(&Base2, &Base2); BigIntNegate(&Base3, &Base3); BigIntNegate(&Base4, &Base4); } // Sort cubes SortBigIntegers(&Base1, &Base2); SortBigIntegers(&Base1, &Base3); SortBigIntegers(&Base1, &Base4); SortBigIntegers(&Base2, &Base3); SortBigIntegers(&Base2, &Base4); SortBigIntegers(&Base3, &Base4); // Validate getSumOfCubes(); // tmpP1 = Base1^3 - Base2^3 - Base3^3 - Base4^3 BigIntSubt(&tmpP1, pArgument, &tmpQ1); if (tmpQ1.nbrLimbs != 1 || tmpQ1.limbs[0].x != 0) { return 1; // Result does not validate. } return 0; }
static enum eExprErr ComputeExpr(char *expr, BigInteger *ExpressionResult) { int i, j, shLeft; int retcode; limb carry; boolean leftNumberFlag = FALSE; int exprIndexAux, offset; enum eExprErr SubExprResult; int len; limb largeLen; limb *ptrLimb; BigInteger factorial; BigInteger *pBigInt; int c; int startStackIndex = stackIndex; exprLength = (int)strlen(expr); while (exprIndex < exprLength) { char charValue; charValue = *(expr+exprIndex); if (charValue == ' ' || charValue == 9) { // Ignore spaces and horizontal tabs. exprIndex++; continue; } if (charValue == '^') { // Caret is exponentiation operation. charValue = OPER_POWER; exprIndex++; } else if (charValue == '*' && *(expr + exprIndex + 1) == '*') { // Double asterisk is exponentiation operation too. charValue = OPER_POWER; exprIndex += 2; } else if (charValue == '*') { charValue = OPER_MULTIPLY; exprIndex++; } else if (charValue == '/') { charValue = OPER_DIVIDE; exprIndex++; } else if (charValue == '%') { charValue = OPER_REMAINDER; exprIndex++; } else if (charValue == '+') { charValue = OPER_PLUS; exprIndex++; } else if (charValue == '-') { charValue = OPER_MINUS; exprIndex++; } else if (charValue == '<' && *(expr + exprIndex + 1) == '=') { charValue = OPER_NOT_GREATER; exprIndex += 2; } else if (charValue == '>' && *(expr + exprIndex + 1) == '=') { charValue = OPER_NOT_LESS; exprIndex += 2; } else if (charValue == '!' && *(expr + exprIndex + 1) == '=') { charValue = OPER_NOT_EQUAL; exprIndex += 2; } else if (charValue == '=' && *(expr + exprIndex + 1) == '=') { charValue = OPER_EQUAL; exprIndex += 2; } else if (charValue == '>') { charValue = OPER_GREATER; exprIndex++; } else if (charValue == '<') { charValue = OPER_LESS; exprIndex++; } else if ((charValue & 0xDF) == 'N' && (*(expr + exprIndex + 1) & 0xDF) == 'O' && (*(expr + exprIndex + 2) & 0xDF) == 'T') { charValue = OPER_NOT; exprIndex += 3; } else if ((charValue & 0xDF) == 'A' && (*(expr + exprIndex + 1) & 0xDF) == 'N' && (*(expr + exprIndex + 2) & 0xDF) == 'D') { charValue = OPER_AND; exprIndex += 3; } else if ((charValue & 0xDF) == 'O' && (*(expr + exprIndex + 1) & 0xDF) == 'R') { charValue = OPER_OR; exprIndex += 2; } else if (charValue == '!') { // Calculating factorial. if (leftNumberFlag == FALSE) { return EXPR_SYNTAX_ERROR; } if (stackValues[stackIndex].nbrLimbs > 1) { return EXPR_INTERM_TOO_HIGH; } if (stackValues[stackIndex].limbs[0].x < 0 || stackValues[stackIndex].limbs[0].x > 5984) { return EXPR_INTERM_TOO_HIGH; } len = (int)stackValues[stackIndex].limbs[0].x; factorial.limbs[0].x = 1; factorial.nbrLimbs = 1; factorial.sign = SIGN_POSITIVE; for (i = 2; i <= len; i++) { // Multiply by all integers up to the argument of factorial. multint(&factorial, &factorial, i); } stackValues[stackIndex] = factorial; exprIndex++; continue; } else if (charValue == '#') { // Calculating primorial. if (leftNumberFlag == FALSE) { return EXPR_SYNTAX_ERROR; } if (stackValues[stackIndex].nbrLimbs > 2) { return EXPR_INTERM_TOO_HIGH; } if (stackValues[stackIndex].nbrLimbs == 2) { largeLen.x = stackValues[stackIndex].limbs[0].x + (stackValues[stackIndex].limbs[1].x << BITS_PER_GROUP); } else { largeLen.x = stackValues[stackIndex].limbs[0].x; } if (largeLen.x < 0 || largeLen.x > 46049) { return EXPR_INTERM_TOO_HIGH; } len = (int)largeLen.x; // Check if number is prime for (i = 2; i*i <= len; i++) { if (len / i*i == len) { // Number is not prime, so go out. return EXPR_INVALID_PARAM; } } factorial.limbs[0].x = 1; factorial.nbrLimbs = 1; factorial.sign = SIGN_POSITIVE; for (i = 2; i <= len; i++) { // Multiply by prime numbers only. for (j = 2; j*j <= i; j++) { if (i / j*j == i) { // Number is not prime. break; } } if (j*j > i) { // Number is prime, perform multiplication. multint(&factorial, &factorial, i); } } stackValues[stackIndex] = factorial; exprIndex++; continue; } else if ((retcode = func(expr, ExpressionResult, "GCD", 2, leftNumberFlag)) <= 0) { if (retcode != 0) { return retcode; } BigIntGcd(&stackValues[stackIndex], &stackValues[stackIndex + 1], &stackValues[stackIndex]); leftNumberFlag = 1; continue; } else if ((retcode = func(expr, ExpressionResult, "MODPOW", 3, leftNumberFlag)) <= 0) { if (retcode != 0) { return retcode; } retcode = BigIntGeneralModularPower(&stackValues[stackIndex], &stackValues[stackIndex + 1], &stackValues[stackIndex + 2], &stackValues[stackIndex]); if (retcode != 0) { return retcode; } leftNumberFlag = 1; continue; } else if ((retcode = func(expr, ExpressionResult, "MODINV", 2, leftNumberFlag)) <= 0) { if (retcode != 0) { return retcode; } retcode = ComputeModInv(); if (retcode != 0) { return retcode; } leftNumberFlag = 1; continue; } #ifdef FACTORIZATION_FUNCTIONS else if ((retcode = func(expr, ExpressionResult, "TOTIENT", 1, leftNumberFlag)) <= 0) { if (retcode != 0) { return retcode; } retcode = ComputeTotient(); if (retcode != 0) { return retcode; } leftNumberFlag = 1; continue; } else if ((retcode = func(expr, ExpressionResult, "NUMDIVS", 1, leftNumberFlag)) <= 0) { if (retcode != 0) { return retcode; } retcode = ComputeNumDivs(); if (retcode != 0) { return retcode; } leftNumberFlag = 1; continue; } else if ((retcode = func(expr, ExpressionResult, "SUMDIVS", 1, leftNumberFlag)) <= 0) { if (retcode != 0) { return retcode; } retcode = ComputeSumDivs(); if (retcode != 0) { return retcode; } leftNumberFlag = 1; continue; } else if ((retcode = func(expr, ExpressionResult, "CONCATFACT", 2, leftNumberFlag)) <= 0) { if (retcode != 0) { return retcode; } retcode = ComputeConcatFact(); if (retcode != 0) { return retcode; } leftNumberFlag = 1; continue; } #endif else if ((retcode = func(expr, ExpressionResult, "SUMDIGITS", 2, leftNumberFlag)) <= 0) { if (retcode != 0) { return retcode; } retcode = ComputeSumDigits(); if (retcode != 0) { return retcode; } leftNumberFlag = 1; continue; } else if ((retcode = func(expr, ExpressionResult, "NUMDIGITS", 2, leftNumberFlag)) <= 0) { if (retcode != 0) { return retcode; } retcode = ComputeNumDigits(); if (retcode != 0) { return retcode; } leftNumberFlag = 1; continue; } else if ((retcode = func(expr, ExpressionResult, "REVDIGITS", 2, leftNumberFlag)) <= 0) { if (retcode != 0) { return retcode; } retcode = ComputeRevDigits(); if (retcode != 0) { return retcode; } leftNumberFlag = 1; continue; } else if ((retcode = func(expr, ExpressionResult, "ISPRIME", 1, leftNumberFlag)) <= 0) { if (retcode != 0) { return retcode; } if (BpswPrimalityTest(&stackValues[stackIndex]) == 0) { // Argument is a probable prime. intToBigInteger(&stackValues[stackIndex], -1); } else { // Argument is not a probable prime. intToBigInteger(&stackValues[stackIndex], 0); } leftNumberFlag = 1; continue; } else if ((retcode = func(expr, ExpressionResult, "F", 1, leftNumberFlag)) <= 0) { if (retcode != 0) { return retcode; } retcode = ComputeFibLucas(0); if (retcode != 0) { return retcode; } leftNumberFlag = 1; continue; } else if ((retcode = func(expr, ExpressionResult, "L", 1, leftNumberFlag)) <= 0) { if (retcode != 0) { return retcode; } retcode = ComputeFibLucas(2); if (retcode != 0) { return retcode; } leftNumberFlag = 1; continue; } else if ((retcode = func(expr, ExpressionResult, "P", 1, leftNumberFlag)) <= 0) { if (retcode != 0) { return retcode; } retcode = ComputePartition(); if (retcode != 0) { return retcode; } leftNumberFlag = 1; continue; } else if ((retcode = func(expr, ExpressionResult, "N", 1, leftNumberFlag)) <= 0) { if (retcode != 0) { return retcode; } retcode = ComputeNext(); if (retcode != 0) { return retcode; } leftNumberFlag = 1; continue; } else if ((retcode = func(expr, ExpressionResult, "B", 1, leftNumberFlag)) <= 0) { if (retcode != 0) { return retcode; } retcode = ComputeBack(); if (retcode != 0) { return retcode; } leftNumberFlag = 1; continue; } else if ((charValue & 0xDF) == 'X') { if (leftNumberFlag || valueX.nbrLimbs == 0) { return EXPR_SYNTAX_ERROR; } CopyBigInt(&stackValues[stackIndex], &valueX); valueXused = TRUE; exprIndex++; leftNumberFlag = TRUE; continue; } else if ((charValue & 0xDF) == 'C') { if (leftNumberFlag || valueX.nbrLimbs == 0) { return EXPR_SYNTAX_ERROR; } intToBigInteger(&stackValues[stackIndex], counterC); valueXused = TRUE; exprIndex++; leftNumberFlag = TRUE; continue; } else if (charValue == '(') { if (leftNumberFlag == TRUE) { return EXPR_SYNTAX_ERROR; } if (stackIndex >= PAREN_STACK_SIZE) { return EXPR_TOO_MANY_PAREN; } stackOperators[stackIndex++] = charValue; exprIndex++; continue; } else if (charValue == ')' || charValue == ',') { if (leftNumberFlag == 0) { return EXPR_SYNTAX_ERROR; } while (stackIndex > startStackIndex && stackOperators[stackIndex - 1] != '(') { if ((SubExprResult = ComputeSubExpr()) != 0) { return SubExprResult; } } if (stackIndex == startStackIndex) { break; } if (charValue == ',') { return EXPR_PAREN_MISMATCH; } stackIndex--; /* Discard ')' */ stackValues[stackIndex] = stackValues[stackIndex + 1]; leftNumberFlag = 1; exprIndex++; continue; } else if (charValue >= '0' && charValue <= '9') { exprIndexAux = exprIndex; if (charValue == '0' && exprIndexAux < exprLength - 2 && *(expr+exprIndexAux + 1) == 'x') { // hexadecimal exprIndexAux++; while (exprIndexAux < exprLength - 1) { charValue = *(expr+exprIndexAux + 1); if ((charValue >= '0' && charValue <= '9') || (charValue >= 'A' && charValue <= 'F') || (charValue >= 'a' && charValue <= 'f')) { exprIndexAux++; } else { break; } } // Generate big integer from hexadecimal number from right to left. carry.x = 0; i = 0; // limb number. shLeft = 0; offset = exprIndexAux; ptrLimb = &stackValues[stackIndex].limbs[0]; for (; exprIndexAux >= exprIndex + 2; exprIndexAux--) { c = *(expr + exprIndexAux); if (c >= '0' && c <= '9') { c -= '0'; } else if (c >= 'A' && c <= 'F') { c -= 'A' - 10; } else { c -= 'a' - 10; } carry.x += c << shLeft; shLeft += 4; // 4 bits per hex digit. if (shLeft >= BITS_PER_GROUP) { shLeft -= BITS_PER_GROUP; (ptrLimb++)->x = carry.x & MAX_VALUE_LIMB; carry.x = c >> (4-shLeft); } } if (carry.x != 0 || ptrLimb == &stackValues[stackIndex].limbs[0]) { (ptrLimb++)->x = carry.x; } exprIndex = offset+1; stackValues[stackIndex].nbrLimbs = (int)(ptrLimb - &stackValues[stackIndex].limbs[0]); stackValues[stackIndex].sign = SIGN_POSITIVE; }