in src/main/java/org/apache/datasketches/quantiles/DoublesMergeImpl.java [143:221]
static void downSamplingMergeInto(final DoublesSketch src, final UpdateDoublesSketch tgt) {
final int sourceK = src.getK();
final int targetK = tgt.getK();
final long tgtN = tgt.getN();
if ((sourceK % targetK) != 0) {
throw new SketchesArgumentException(
"source.getK() must equal target.getK() * 2^(nonnegative integer).");
}
final int downFactor = sourceK / targetK;
checkIfPowerOf2(downFactor, "source.getK()/target.getK() ratio");
final int lgDownFactor = Integer.numberOfTrailingZeros(downFactor);
if (src.isEmpty()) { return; }
final DoublesSketchAccessor srcSketchBuf = DoublesSketchAccessor.wrap(src);
final long nFinal = tgtN + src.getN();
for (int i = 0; i < srcSketchBuf.numItems(); i++) { // update only the base buffer
tgt.update(srcSketchBuf.get(i));
}
final int spaceNeeded = DoublesUpdateImpl.getRequiredItemCapacity(targetK, nFinal);
final int curCombBufCap = tgt.getCombinedBufferItemCapacity();
if (spaceNeeded > curCombBufCap) { //copies base buffer plus current levels
tgt.growCombinedBuffer(curCombBufCap, spaceNeeded);
}
//working scratch buffers
final DoublesArrayAccessor scratch2KAcc = DoublesArrayAccessor.initialize(2 * targetK);
final DoublesArrayAccessor downScratchKAcc = DoublesArrayAccessor.initialize(targetK);
final DoublesSketchAccessor tgtSketchBuf = DoublesSketchAccessor.wrap(tgt, true);
long srcBitPattern = src.getBitPattern();
long newTgtBitPattern = tgt.getBitPattern();
for (int srcLvl = 0; srcBitPattern != 0L; srcLvl++, srcBitPattern >>>= 1) {
if ((srcBitPattern & 1L) > 0L) {
justZipWithStride(
srcSketchBuf.setLevel(srcLvl),
downScratchKAcc,
targetK,
downFactor
);
newTgtBitPattern = DoublesUpdateImpl.inPlacePropagateCarry(
srcLvl + lgDownFactor, //starting level
downScratchKAcc, //optSrcKBuf,
scratch2KAcc, //size2KBuf,
false, //do mergeInto version
targetK,
tgtSketchBuf,
newTgtBitPattern
);
tgt.putBitPattern(newTgtBitPattern); //off-heap is a no-op
}
}
if (tgt.hasMemory() && (nFinal > 0)) {
final WritableMemory mem = tgt.getMemory();
mem.clearBits(FLAGS_BYTE, (byte) EMPTY_FLAG_MASK);
}
tgt.putN(nFinal);
assert (tgt.getN() / (2L * targetK)) == newTgtBitPattern; // internal consistency check
double srcMax = src.getMaxItem();
srcMax = Double.isNaN(srcMax) ? Double.NEGATIVE_INFINITY : srcMax;
double srcMin = src.getMinItem();
srcMin = Double.isNaN(srcMin) ? Double.POSITIVE_INFINITY : srcMin;
double tgtMax = tgt.getMaxItem();
tgtMax = Double.isNaN(tgtMax) ? Double.NEGATIVE_INFINITY : tgtMax;
double tgtMin = tgt.getMinItem();
tgtMin = Double.isNaN(tgtMin) ? Double.POSITIVE_INFINITY : tgtMin;
if (srcMax > tgtMax) { tgt.putMaxItem(srcMax); }
if (srcMin < tgtMin) { tgt.putMinItem(srcMin); }
}