void GaussianFactorization(void) { BigInteger prime, q, r, M1, M2, Tmp; struct sFactors *pstFactor; BigIntMultiply(&ReValue, &ReValue, &tofactor); BigIntMultiply(&ImValue, &ImValue, &Tmp); BigIntAdd(&tofactor, &Tmp, &tofactor); NbrFactorsNorm = 0; #ifdef __EMSCRIPTEN__ originalTenthSecond = tenths(); #endif if (tofactor.nbrLimbs == 1 && tofactor.limbs[0].x == 0) { // Norm is zero. w("<ul><li>Any gaussian prime divides this number</li></ul>"); return; } w("<ul>"); if (tofactor.nbrLimbs > 1 || tofactor.limbs[0].x > 1) { // norm greater than 1. Factor norm. int index, index2; char *ptrFactorDec = tofactorDec; NumberLength = tofactor.nbrLimbs; CompressBigInteger(nbrToFactor, &tofactor); strcpy(ptrFactorDec, "Re² + Im² = "); ptrFactorDec += strlen(ptrFactorDec); Bin2Dec(ReValue.limbs, ptrFactorDec, ReValue.nbrLimbs, groupLen); ptrFactorDec += strlen(ptrFactorDec); strcpy(ptrFactorDec, "² + "); ptrFactorDec += strlen(ptrFactorDec); Bin2Dec(ImValue.limbs, ptrFactorDec, ImValue.nbrLimbs, groupLen); ptrFactorDec += strlen(ptrFactorDec); strcpy(ptrFactorDec, "²"); ptrFactorDec += strlen(ptrFactorDec); factor(&tofactor, nbrToFactor, factorsNorm, astFactorsNorm, NULL); NbrFactorsNorm = astFactorsNorm[0].multiplicity; pstFactor = &astFactorsNorm[1]; for (index = 0; index < NbrFactorsNorm; index++) { int *ptrPrime = pstFactor->ptrFactor; NumberLength = *ptrPrime; UncompressBigInteger(ptrPrime, &prime); prime.sign = SIGN_POSITIVE; if (prime.nbrLimbs == 1 && prime.limbs[0].x == 2) { // Prime factor is 2. for (index2 = 0; index2 < pstFactor->multiplicity; index2++) { M1.nbrLimbs = M2.nbrLimbs = 1; M1.limbs[0].x = M2.limbs[0].x = 1; M1.sign = SIGN_POSITIVE; M2.sign = SIGN_NEGATIVE; DivideGaussian(&M1, &M1); // Divide by 1+i DivideGaussian(&M1, &M2); // Divide by 1-i } } if ((prime.limbs[0].x & 2) == 0) { // Prime is congruent to 1 (mod 4) CopyBigInt(&q, &prime); NumberLength = prime.nbrLimbs; memcpy(&TestNbr, prime.limbs, NumberLength * sizeof(limb)); TestNbr[NumberLength].x = 0; GetMontgomeryParms(NumberLength); subtractdivide(&q, 1, 4); // q = (prime-1)/4 memset(&K, 0, NumberLength * sizeof(limb)); memset(minusOneMont, 0, NumberLength * sizeof(limb)); SubtBigNbrModN(minusOneMont, MontgomeryMultR1, minusOneMont, TestNbr, NumberLength); K[0].x = 1; do { // Loop that finds mult1 = sqrt(-1) mod prime in Montgomery notation. K[0].x++; modPow(K, q.limbs, q.nbrLimbs, mult1.limbs); } while (!memcmp(mult1.limbs, MontgomeryMultR1, NumberLength * sizeof(limb)) || !memcmp(mult1.limbs, minusOneMont, NumberLength * sizeof(limb))); K[0].x = 1; modmult(mult1.limbs, K, mult1.limbs); // Convert mult1 to standard notation. UncompressLimbsBigInteger(mult1.limbs, &mult1); // Convert to Big Integer. mult2.nbrLimbs = 1; // mult2 <- 1 mult2.limbs[0].x = 1; mult2.sign = SIGN_POSITIVE; for (;;) { // norm <- (mult1^2 + mult2^2) / prime BigIntMultiply(&mult1, &mult1, &tofactor); BigIntMultiply(&mult2, &mult2, &Tmp); BigIntAdd(&tofactor, &Tmp, &Tmp); BigIntDivide(&Tmp, &prime, &tofactor); if (tofactor.nbrLimbs == 1 && tofactor.limbs[0].x == 1) { // norm equals 1. break; } BigIntRemainder(&mult1, &tofactor, &M1); BigIntRemainder(&mult2, &tofactor, &M2); BigIntAdd(&M1, &M1, &Tmp); BigIntSubt(&tofactor, &Tmp, &Tmp); if (Tmp.sign == SIGN_NEGATIVE) { BigIntSubt(&M1, &tofactor, &M1); } BigIntAdd(&M2, &M2, &Tmp); BigIntSubt(&tofactor, &Tmp, &Tmp); if (Tmp.sign == SIGN_NEGATIVE) { BigIntSubt(&M2, &tofactor, &M2); } // Compute q <- (mult1*M1 + mult2*M2) / norm BigIntMultiply(&mult1, &M1, &q); BigIntMultiply(&mult2, &M2, &Tmp); BigIntAdd(&q, &Tmp, &Tmp); BigIntDivide(&Tmp, &tofactor, &q); // Compute Mult2 <- (mult1*M2 - mult2*M1) / tofactor BigIntMultiply(&mult1, &M2, &r); BigIntMultiply(&mult2, &M1, &Tmp); BigIntSubt(&r, &Tmp, &Tmp); BigIntDivide(&Tmp, &tofactor, &mult2); CopyBigInt(&mult1, &q); mult1.sign = SIGN_POSITIVE; // mult1 <- abs(mult1) mult2.sign = SIGN_POSITIVE; // mult2 <- abs(mult2) } /* end while */ CopyBigInt(&M1, &mult1); CopyBigInt(&M2, &mult2); BigIntSubt(&M1, &M2, &Tmp); if (Tmp.sign == SIGN_NEGATIVE) { CopyBigInt(&Tmp, &mult1); CopyBigInt(&mult1, &mult2); CopyBigInt(&mult2, &Tmp); } for (index2 = 0; index2 < pstFactor->multiplicity; index2++) { DivideGaussian(&mult1, &mult2); BigIntNegate(&mult2, &Tmp); DivideGaussian(&mult1, &Tmp); } } // end p = 1 (mod 4) else { // if p = 3 (mod 4) q.nbrLimbs = 1; // q <- 0 q.limbs[0].x = 0; q.sign = SIGN_POSITIVE; for (index2 = 0; index2 < pstFactor->multiplicity; index2++) { DivideGaussian(&prime, &q); } // end p = 3 (mod 4) } pstFactor++; } } // Process units: 1, -1, i, -i. if (ReValue.nbrLimbs == 1 && ReValue.limbs[0].x == 1) { if (ReValue.sign == SIGN_POSITIVE) { // Value is 1. if (NbrFactorsNorm == 0) { w("No gaussian prime divides this number"); } } else { // Value is -1. w("<li>-1</li>"); } } else if (ImValue.sign == SIGN_POSITIVE) { w("<li>i</li>"); } else { w("<li>-i</li>"); } w("</ul>"); }
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; }