Skip to content

Commit ea1e9b2

Browse files
authored
Merge pull request #5819 from MartinNowak/merge_stable
Merge remote-tracking branch 'upstream/stable' into merge_stable
2 parents 8e4dfdb + 3832162 commit ea1e9b2

File tree

2 files changed

+117
-51
lines changed

2 files changed

+117
-51
lines changed

std/bigint.d

Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -311,6 +311,55 @@ public:
311311
assert(b == BigInt("200_002_469"));
312312
}
313313

314+
// Issue 16264
315+
@system unittest
316+
{
317+
auto a = BigInt(
318+
`335690982744637013564796917901053301979460129353374296317539383938630086938` ~
319+
`465898213033510992292836631752875403891802201862860531801760096359705447768` ~
320+
`957432600293361240407059207520920532482429912948952142341440301429494694368` ~
321+
`264560802292927144211230021750155988283029753927847924288850436812178022006` ~
322+
`408597793414273953252832688620479083497367463977081627995406363446761896298` ~
323+
`967177607401918269561385622811274398143647535024987050366350585544531063531` ~
324+
`7118554808325723941557169427279911052268935775`);
325+
326+
auto b = BigInt(
327+
`207672245542926038535480439528441949928508406405023044025560363701392340829` ~
328+
`852529131306106648201340460604257466180580583656068555417076345439694125326` ~
329+
`843947164365500055567495554645796102453565953360564114634705366335703491527` ~
330+
`429426780005741168078089657359833601261803592920462081364401456331489106355` ~
331+
`199133982282631108670436696758342051198891939367812305559960349479160308314` ~
332+
`068518200681530999860641597181672463704794566473241690395901768680673716414` ~
333+
`243691584391572899147223065906633310537507956952626106509069491302359792769` ~
334+
`378934570685117202046921464019396759638376362935855896435623442486036961070` ~
335+
`534574698959398017332214518246531363445309522357827985468581166065335726996` ~
336+
`711467464306784543112544076165391268106101754253962102479935962248302404638` ~
337+
`21737237102628470475027851189594709504`);
338+
339+
BigInt c = a * b; // Crashes
340+
341+
assert(c == BigInt(
342+
`697137001950904057507249234183127244116872349433141878383548259425589716813` ~
343+
`135440660252012378417669596912108637127036044977634382385990472429604619344` ~
344+
`738746224291111527200379708978133071390303850450970292020176369525401803474` ~
345+
`998613408923490273129022167907826017408385746675184651576154302536663744109` ~
346+
`111018961065316024005076097634601030334948684412785487182572502394847587887` ~
347+
`507385831062796361152176364659197432600147716058873232435238712648552844428` ~
348+
`058885217631715287816333209463171932255049134340904981280717725999710525214` ~
349+
`161541960645335744430049558161514565159449390036287489478108344584188898872` ~
350+
`434914159748515512161981956372737022393466624249130107254611846175580584736` ~
351+
`276213025837422102290580044755202968610542057651282410252208599309841499843` ~
352+
`672251048622223867183370008181364966502137725166782667358559333222947265344` ~
353+
`524195551978394625568228658697170315141077913403482061673401937141405425042` ~
354+
`283546509102861986303306729882186190883772633960389974665467972016939172303` ~
355+
`653623175801495207204880400522581834672918935651426160175413277309985678579` ~
356+
`830872397214091472424064274864210953551447463312267310436493480881235642109` ~
357+
`668498742629676513172286703948381906930297135997498416573231570483993847269` ~
358+
`479552708416124555462530834668011570929850407031109157206202741051573633443` ~
359+
`58105600`
360+
));
361+
}
362+
314363
/**
315364
* Implements assignment operators of the form $(D BigInt op= BigInt).
316365
*/

std/internal/math/biguintcore.d

Lines changed: 68 additions & 51 deletions
Original file line numberDiff line numberDiff line change
@@ -1402,59 +1402,76 @@ void mulInternal(BigDigit[] result, const(BigDigit)[] x, const(BigDigit)[] y)
14021402
auto extra = x.length % y.length;
14031403
auto maxchunk = chunksize + extra;
14041404
bool paddingY; // true = we're padding Y, false = we're padding X.
1405-
if (extra * extra * 2 < y.length*y.length)
1406-
{
1407-
// The leftover bit is small enough that it should be incorporated
1408-
// in the existing chunks.
1409-
// Make all the chunks a tiny bit bigger
1410-
// (We're padding y with zeros)
1411-
chunksize += extra / numchunks;
1412-
extra = x.length - chunksize*numchunks;
1413-
// there will probably be a few left over.
1414-
// Every chunk will either have size chunksize, or chunksize+1.
1415-
maxchunk = chunksize + 1;
1416-
paddingY = true;
1417-
assert(chunksize + extra + chunksize *(numchunks-1) == x.length );
1405+
bool isExtraSmall = extra * extra * 2 < y.length * y.length;
1406+
if (numchunks == 1 && isExtraSmall)
1407+
{
1408+
// We divide (x_first_half * y) and (x_last_half * y)
1409+
// between 1.414:1 and 1.707:1 (1.707 = 1+1/sqrt(2)).
1410+
// (1.414 ~ 1.707)/2:1 is balanced.
1411+
BigDigit [] scratchbuff = new BigDigit[karatsubaRequiredBuffSize(y.length) + y.length];
1412+
BigDigit [] partial = scratchbuff[$ - y.length .. $];
1413+
mulKaratsuba(result[0 .. half + y.length], y, x[0 .. half], scratchbuff);
1414+
partial[] = result[half .. half + y.length];
1415+
mulKaratsuba(result[half .. $], y, x[half .. $], scratchbuff);
1416+
addAssignSimple(result[half .. half + y.length], partial);
1417+
() @trusted { GC.free(scratchbuff.ptr); } ();
14181418
}
14191419
else
14201420
{
1421-
// the extra bit is large enough that it's worth making a new chunk.
1422-
// (This means we're padding x with zeros, when doing the first one).
1423-
maxchunk = chunksize;
1424-
++numchunks;
1425-
paddingY = false;
1426-
assert(extra + chunksize *(numchunks-1) == x.length );
1427-
}
1428-
// We make the buffer a bit bigger so we have space for the partial sums.
1429-
BigDigit [] scratchbuff = new BigDigit[karatsubaRequiredBuffSize(maxchunk) + y.length];
1430-
BigDigit [] partial = scratchbuff[$ - y.length .. $];
1431-
size_t done; // how much of X have we done so far?
1432-
if (paddingY)
1433-
{
1434-
// If the first chunk is bigger, do it first. We're padding y.
1435-
mulKaratsuba(result[0 .. y.length + chunksize + (extra > 0 ? 1 : 0 )],
1436-
x[0 .. chunksize + (extra>0?1:0)], y, scratchbuff);
1437-
done = chunksize + (extra > 0 ? 1 : 0);
1438-
if (extra) --extra;
1439-
}
1440-
else
1441-
{ // We're padding X. Begin with the extra bit.
1442-
mulKaratsuba(result[0 .. y.length + extra], y, x[0 .. extra], scratchbuff);
1443-
done = extra;
1444-
extra = 0;
1445-
}
1446-
immutable basechunksize = chunksize;
1447-
while (done < x.length)
1448-
{
1449-
chunksize = basechunksize + (extra > 0 ? 1 : 0);
1450-
if (extra) --extra;
1451-
partial[] = result[done .. done+y.length];
1452-
mulKaratsuba(result[done .. done + y.length + chunksize],
1453-
x[done .. done+chunksize], y, scratchbuff);
1454-
addAssignSimple(result[done .. done + y.length + chunksize], partial);
1455-
done += chunksize;
1421+
if (isExtraSmall)
1422+
{
1423+
// The leftover bit is small enough that it should be incorporated
1424+
// in the existing chunks.
1425+
// Make all the chunks a tiny bit bigger
1426+
// (We're padding y with zeros)
1427+
chunksize += extra / numchunks;
1428+
extra = x.length - chunksize*numchunks;
1429+
// there will probably be a few left over.
1430+
// Every chunk will either have size chunksize, or chunksize+1.
1431+
maxchunk = chunksize + 1;
1432+
paddingY = true;
1433+
assert(chunksize + extra + chunksize *(numchunks-1) == x.length );
1434+
}
1435+
else
1436+
{
1437+
// the extra bit is large enough that it's worth making a new chunk.
1438+
// (This means we're padding x with zeros, when doing the first one).
1439+
maxchunk = chunksize;
1440+
++numchunks;
1441+
paddingY = false;
1442+
assert(extra + chunksize *(numchunks-1) == x.length );
1443+
}
1444+
// We make the buffer a bit bigger so we have space for the partial sums.
1445+
BigDigit [] scratchbuff = new BigDigit[karatsubaRequiredBuffSize(maxchunk) + y.length];
1446+
BigDigit [] partial = scratchbuff[$ - y.length .. $];
1447+
size_t done; // how much of X have we done so far?
1448+
if (paddingY)
1449+
{
1450+
// If the first chunk is bigger, do it first. We're padding y.
1451+
mulKaratsuba(result[0 .. y.length + chunksize + (extra > 0 ? 1 : 0 )],
1452+
x[0 .. chunksize + (extra>0?1:0)], y, scratchbuff);
1453+
done = chunksize + (extra > 0 ? 1 : 0);
1454+
if (extra) --extra;
1455+
}
1456+
else
1457+
{ // We're padding X. Begin with the extra bit.
1458+
mulKaratsuba(result[0 .. y.length + extra], y, x[0 .. extra], scratchbuff);
1459+
done = extra;
1460+
extra = 0;
1461+
}
1462+
immutable basechunksize = chunksize;
1463+
while (done < x.length)
1464+
{
1465+
chunksize = basechunksize + (extra > 0 ? 1 : 0);
1466+
if (extra) --extra;
1467+
partial[] = result[done .. done+y.length];
1468+
mulKaratsuba(result[done .. done + y.length + chunksize],
1469+
x[done .. done+chunksize], y, scratchbuff);
1470+
addAssignSimple(result[done .. done + y.length + chunksize], partial);
1471+
done += chunksize;
1472+
}
1473+
() @trusted { GC.free(scratchbuff.ptr); } ();
14561474
}
1457-
() @trusted { GC.free(scratchbuff.ptr); } ();
14581475
}
14591476
else
14601477
{
@@ -1963,7 +1980,7 @@ bool less(const(BigDigit)[] x, const(BigDigit)[] y) pure nothrow
19631980
bool inplaceSub(BigDigit[] result, const(BigDigit)[] x, const(BigDigit)[] y)
19641981
pure nothrow
19651982
{
1966-
assert(result.length == (x.length >= y.length) ? x.length : y.length);
1983+
assert(result.length == ((x.length >= y.length) ? x.length : y.length));
19671984

19681985
size_t minlen;
19691986
bool negative;
@@ -2021,7 +2038,7 @@ void mulKaratsuba(BigDigit [] result, const(BigDigit) [] x,
20212038
const(BigDigit)[] y, BigDigit [] scratchbuff) pure nothrow
20222039
{
20232040
assert(x.length >= y.length);
2024-
assert(result.length < uint.max, "Operands too large");
2041+
assert(result.length < uint.max, "Operands too large");
20252042
assert(result.length == x.length + y.length);
20262043
if (x.length <= KARATSUBALIMIT)
20272044
{

0 commit comments

Comments
 (0)