Skip to content

Commit 832578f

Browse files
committed
Implement Karatsuba's multiplication algorithm
Only implemented for unsigned 8/16/32-bit multiplication. Requires full performance benchmarking and possibly also a review for optimisations.
1 parent fb9b874 commit 832578f

File tree

2 files changed

+54
-0
lines changed

2 files changed

+54
-0
lines changed

src/solvers/flattening/bv_utils.cpp

Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1817,6 +1817,50 @@ bvt bv_utilst::unsigned_multiplier(const bvt &_op0, const bvt &_op1)
18171817
}
18181818
}
18191819

1820+
bvt bv_utilst::unsigned_karatsuba_multiplier(const bvt &_op0, const bvt &_op1)
1821+
{
1822+
if(_op0.size() != _op1.size())
1823+
return unsigned_multiplier(_op0, _op1);
1824+
1825+
const std::size_t op_size = _op0.size();
1826+
if(op_size != 32 && op_size != 16 && op_size != 8)
1827+
return unsigned_multiplier(_op0, _op1);
1828+
1829+
const std::size_t half_op_size = op_size >> 1;
1830+
1831+
bvt x0{_op0.begin(), _op0.begin() + half_op_size};
1832+
x0.resize(op_size, const_literal(false));
1833+
bvt x1{_op0.begin() + half_op_size, _op0.end()};
1834+
// x1.resize(op_size, const_literal(false));
1835+
bvt y0{_op1.begin(), _op1.begin() + half_op_size};
1836+
y0.resize(op_size, const_literal(false));
1837+
bvt y1{_op1.begin() + half_op_size, _op1.end()};
1838+
// y1.resize(op_size, const_literal(false));
1839+
1840+
bvt z0 = unsigned_multiplier(x0, y0);
1841+
bvt z2 = unsigned_karatsuba_multiplier(x1, y1);
1842+
1843+
bvt z0_half{z0.begin(), z0.begin() + half_op_size};
1844+
bvt z2_plus_z0 = add(z2, z0_half);
1845+
z2_plus_z0.resize(half_op_size);
1846+
1847+
bvt x0_half{x0.begin(), x0.begin() + half_op_size};
1848+
bvt xdiff = add(x0_half, x1);
1849+
// xdiff.resize(half_op_size);
1850+
bvt y0_half{y0.begin(), y0.begin() + half_op_size};
1851+
bvt ydiff = add(y1, y0_half);
1852+
// ydiff.resize(half_op_size);
1853+
1854+
bvt z1 = sub(unsigned_karatsuba_multiplier(xdiff, ydiff), z2_plus_z0);
1855+
for(std::size_t i = 0; i < half_op_size; ++i)
1856+
z1.insert(z1.begin(), const_literal(false));
1857+
// result.insert(result.end(), z1.begin(), z1.end());
1858+
1859+
// z1.resize(op_size);
1860+
z0.resize(op_size);
1861+
return add(z0, z1);
1862+
}
1863+
18201864
bvt bv_utilst::unsigned_multiplier_no_overflow(
18211865
const bvt &op0,
18221866
const bvt &op1)
@@ -1867,7 +1911,11 @@ bvt bv_utilst::signed_multiplier(const bvt &op0, const bvt &op1)
18671911
bvt neg0=cond_negate(op0, sign0);
18681912
bvt neg1=cond_negate(op1, sign1);
18691913

1914+
#ifdef USE_KARATSUBA
1915+
bvt result = unsigned_karatsuba_multiplier(neg0, neg1);
1916+
#else
18701917
bvt result=unsigned_multiplier(neg0, neg1);
1918+
#endif
18711919

18721920
literalt result_sign=prop.lxor(sign0, sign1);
18731921

@@ -1935,7 +1983,12 @@ bvt bv_utilst::multiplier(
19351983
switch(rep)
19361984
{
19371985
case representationt::SIGNED: return signed_multiplier(op0, op1);
1986+
#ifdef USE_KARATSUBA
1987+
case representationt::UNSIGNED:
1988+
return unsigned_karatsuba_multiplier(op0, op1);
1989+
#else
19381990
case representationt::UNSIGNED: return unsigned_multiplier(op0, op1);
1991+
#endif
19391992
}
19401993

19411994
UNREACHABLE;

src/solvers/flattening/bv_utils.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -80,6 +80,7 @@ class bv_utilst
8080
bvt shift(const bvt &op, const shiftt shift, const bvt &distance);
8181

8282
bvt unsigned_multiplier(const bvt &op0, const bvt &op1);
83+
bvt unsigned_karatsuba_multiplier(const bvt &op0, const bvt &op1);
8384
bvt signed_multiplier(const bvt &op0, const bvt &op1);
8485
bvt multiplier(const bvt &op0, const bvt &op1, representationt rep);
8586
bvt multiplier_no_overflow(

0 commit comments

Comments
 (0)