Re: Toom Cook 3 Multiplication Algorithm Return Wrong Result
I have run through my program twice and correct the faster evaluation
sequence but i still can't find problem that cause the calculation
return incorrect result.
The exact Interpolation sequence is
r0 $B"+(B r(0) = 3084841486175176
r4 $B"+(B r($B!g(B) = 12193131840
r3 $B"+(B (r($B!](B2) $B!](B r(1))/3
= (3188843994597408 $B!](B 13260814415903778)/3
= 3357323473768790
r1 $B"+(B (r(1) $B!](B r($B!](B1))/2
= (13260814415903778 $B!](B ($B!](B246273893346042))/2
= 6753544154624910
r2 $B"+(B r($B!](B1) $B!](B r(0)
= $B!](B246273893346042 $B!](B 3084841486175176
= $B!](B3331115379521218
r3 $B"+(B (r2 $B!](B r3)/2 + 2r($B!g(B)
= ($B!](B3331115379521218 $B!](B ($B!](B3357323473768790))/2 + 2$B!_(B12193131840
= 13128433387466
r2 $B"+(B r2 + r1 $B!](B r($B!g(B)
= $B!](B3331115379521218 + 6753544154624910 $B!](B 12193131840
= 3422416581971852
r1 $B"+(B r1 $B!](B r3
= 6753544154624910 $B!](B 13128433387466
= 6740415721237444
I skip the first two sequence due to it's a self assignment.
Below is my program.
[code]
#include "ToomCook.h"
#include <iostream>
#include <vector>
#include <set>
#include <algorithm>
#include <cstdlib>
#include <cmath>
// =========================================
ToomCook::ToomCook()
: firstNumber(0), secondNumber(0), result(0),
firstNumberSplit(std::vector<ulong>()),
secondNumberSplit(std::vector<ulong>()),
firstPolynomial(std::vector<ulong>(5)),
secondPolynomial(std::vector<ulong>(5)),
resultPolynomial(std::vector<ulong>(5)),
point(std::set<int>()),
firstLength(0), secondLength(0),
firstBaseLength(0), secondBaseLength(0)
{
point.insert(0);
point.insert(1);
point.insert(-1);
point.insert(-2);
// infinity
point.insert(-1);
}
// =========================================
ToomCook::ToomCook(const ulong& firstUserNumber, const ulong&
secondUserNumber)
: firstNumber(firstUserNumber), secondNumber(secondUserNumber), result
(0),
firstNumberSplit(std::vector<ulong>()),
secondNumberSplit(std::vector<ulong>()),
firstPolynomial(std::vector<ulong>(5)),
secondPolynomial(std::vector<ulong>(5)),
resultPolynomial(std::vector<ulong>(5)),
point(std::set<int>()),
firstLength(0), secondLength(0),
firstBaseLength(0), secondBaseLength(0)
{
point.insert(0);
point.insert(1);
point.insert(-1);
point.insert(-2);
// infinity
point.insert(-1);
}
// =========================================
void ToomCook::Multiply()
{
Split();
Evaluation();
PointWiseMult();
Interpolation();
Recomposition();
}
// =========================================
void ToomCook::Split()
{
const int TOOMCOOK3 = 3;
computeLength(this->firstNumber);
firstBaseLength = (this->firstLength + 2) / TOOMCOOK3;
ulong tempNumber(0);
tempNumber = separate(firstNumberSplit, firstNumber,
firstBaseLength);
tempNumber = separate(firstNumberSplit, tempNumber, firstBaseLength);
tempNumber = separate(firstNumberSplit, tempNumber, firstBaseLength);
computeLength(this->secondNumber);
secondBaseLength = (this->secondLength + 2) / TOOMCOOK3;
tempNumber = separate(secondNumberSplit, secondNumber,
secondBaseLength);
tempNumber = separate(secondNumberSplit, tempNumber,
secondBaseLength);
tempNumber = separate(secondNumberSplit, tempNumber,
secondBaseLength);
}
// =========================================
void ToomCook::Evaluation()
{
Evaluating(firstNumberSplit, firstPolynomial);
Evaluating(secondNumberSplit, secondPolynomial);
}
// =========================================
void ToomCook::PointWiseMult()
{
// fake variable to turn off error
ulong first(12345), second(12345);
Karatsuba(first, second);
}
// =========================================
void ToomCook::Interpolation()
{
resultPolynomial[3] = (resultPolynomial[3] - resultPolynomial[1]) /
3;
resultPolynomial[1] = (resultPolynomial[1] - resultPolynomial[2]) /
2;
resultPolynomial[2] = resultPolynomial[2] - resultPolynomial[0];
resultPolynomial[3] = ((resultPolynomial[2] - resultPolynomial[3])/2)
+ (2 * resultPolynomial[4]);
resultPolynomial[2] = resultPolynomial[2] + resultPolynomial[1] -
resultPolynomial[4];
resultPolynomial[1] = resultPolynomial[1] - resultPolynomial[3];
/*
r3 = (r(-2) - r(1)) / 3
r1 = (r(1) - r(-1)) / 2
r2 = r(-1) - r(0)
r3 = (r2 - r3) / 2 + 2r(4)
r2 = r2 + r1 - r(4)
r1 = r1 $B!](B r3
*/
}
// =========================================
void ToomCook::Recomposition()
{
}
// =========================================
void ToomCook::computeLength(ulong number)
{
if (firstLength == 0)
{
while (number / 10 )
{
number /= 10;
++firstLength;
}
}
else
{
while (number / 10 )
{
number /= 10;
++secondLength;
}
}
}
// =========================================
ulong ToomCook::separate(std::vector<ulong>& numberSplit,
ulong number, const size_t& baseLength)
{
size_t countLoop(0);
ulong tempNumber(number);
std::vector<ulong> tempSplit;
while (countLoop < baseLength)
{
tempSplit.push_back(tempNumber % 10);
tempNumber /= 10;
++countLoop;
}
std::reverse(tempSplit.begin(), tempSplit.end());
merge(tempSplit);
numberSplit.push_back(tempSplit[0]);
return tempNumber;
}
// =========================================
void ToomCook::merge(std::vector<ulong>& number)
{
size_t loop(0);
while (loop < number.size() - 1)
{
number[0] = (number[0] * 10) + number[loop + 1];
++loop;
}
number.erase(number.begin() + 1, number.end());
std::vector<ulong>(number).swap(number);
}
// =========================================
void ToomCook::Evaluating(const std::vector<ulong>& number,
std::vector<ulong>& polynomial)
{
// Bodrato approach
if (number.size() > 2 && polynomial.size() > 4)
{
polynomial[0] = number[0] + number[2];
polynomial[1] = polynomial[0] + number[1];
polynomial[2] = polynomial[0] - number[1];
polynomial[3] = ((polynomial[2] + number[2]) * 2) - number[0];
polynomial[0] = number[0];
polynomial[4] = number[2];
}
/*
Bodrato Evaluation Sequence
p0 = m0 + m2
p(1) = m0 + m2
p(-1) = p0 - m1
p(-2) = (p(-1) + m2) x 2 - m0
p(0) = m0
p(infinity) = m2
*/
/*
General Approach
p(0) = m0 + m1(0) + m2(0 ^ 2)
= m0
p(1) = m0(1) + m1(1) + m2(1 ^ 2)
p(-1) = m0(-1) + m1(-1) + m2(-1 ^ 2)
= m0 - m1 + m2
p(-2) = m0(-2) + m1(-2) + m2(-2 ^ 2)
= m0 -2m1 + 4m2
P(infinity) = m2
*/
}
// =========================================
ulong ToomCook::Karatsuba(ulong first, ulong second)
{
const int MINLENGTH = 2;
if (this->firstBaseLength > MINLENGTH &&
this->secondBaseLength > MINLENGTH)
{
if (ComputePolynomialLength(first) > MINLENGTH &&
ComputePolynomialLength(second) > MINLENGTH)
{
int loop(0);
while (loop < static_cast<int>(firstPolynomial.size()) &&
static_cast<int>(secondPolynomial.size()) )
{
ulong x1 = leftSplit(firstPolynomial[loop], ComputePolynomialLength
(firstPolynomial[loop]));
ulong y1 = leftSplit(secondPolynomial[loop],
ComputePolynomialLength(secondPolynomial[loop]));
// wrong here
ulong x0 = rightSplit(firstPolynomial[loop],
ComputePolynomialLength(firstPolynomial[loop]) -
ComputePolynomialLength(x1));
ulong y0 = rightSplit(secondPolynomial[loop],
ComputePolynomialLength(secondPolynomial[loop]) -
ComputePolynomialLength(y1));
int lengthPower = numberPower(firstPolynomial[loop], x1, x0);
ulong X = Karatsuba(x1, y1);
ulong Y = Karatsuba(x0, y0);
ulong Z = Karatsuba(x1 + x0, y1 + y0);
Z = Z - X - Y;
resultPolynomial[loop] = (X * static_cast<unsigned long>(pow(10.0,
2.0 * lengthPower))) +
(Z * static_cast<unsigned long>(pow(10.0, lengthPower))) + Y;
++loop;
}
}
else
{
return first * second;
}
}
else // Base Length < 4
{
if (firstPolynomial.size() > 4 &&
secondPolynomial.size() > 4 &&
resultPolynomial.size() > 4)
{
resultPolynomial[0] = firstPolynomial[0] * secondPolynomial[0];
resultPolynomial[1] = firstPolynomial[1] * secondPolynomial[1];
resultPolynomial[2] = firstPolynomial[2] * secondPolynomial[2];
resultPolynomial[3] = firstPolynomial[3] * secondPolynomial[3];
resultPolynomial[4] = firstPolynomial[4] * secondPolynomial[4];
}
}
return 1;
}
// =========================================
int ToomCook::ComputePolynomialLength(ulong number)
{
int len(0);
// Check length of integer algorithm
// * 10 = To shift left 1 digit in number
// % 10 = To get last digit of number
while (number >= 1)
{
number /= 10;
++len;
}
return len;
}
// =========================================
ulong ToomCook::leftSplit(ulong number, const int& length)
{
int middle = length / 2;
std::vector<ulong> remainder(0);
// To get most significant digit
while (number >= 10)
{
remainder.push_back(number % 10);
number /= 10;
}
std::reverse(remainder.begin(), remainder.end());
ulong result(number);int remLoop(0);
for (int loop = 0;loop < middle - 1;++loop)
{
if (remLoop < static_cast<int>(remainder.size()))
{
result = result * 10 + remainder[remLoop];
}
++remLoop;
}
return result;
}
// =========================================
ulong ToomCook::rightSplit(ulong number, const int& length)
{
ulong remainder(0), multiply(1);
ulong result(0);
for (int loop = 0; loop < length;++loop)
{
remainder = number % 10;
number /= 10;
result += remainder * multiply ;
multiply *= 10;
}
return result;
}
// =========================================
int ToomCook::numberPower(const ulong& first, const ulong& x1,
const ulong& y1) const
{
int lengthPower(1);
const int base(10);
while (first - y1 != (x1 * (pow(static_cast<double>(base),
static_cast<int>(lengthPower)))) )
{
++lengthPower;
}
return lengthPower;
}
// =========================================
// =========================================
// =========================================
// =========================================
// =========================================
[/code]
I hope someone who have eagle eye that can spot my error.
Thanks.
--
[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]