Math-Ryu
view release on metacpan or search on metacpan
Ryu_Library/ryu/d2fixed.c view on Meta::CPAN
}
if (precision > 0) {
result[index++] = '.';
}
#ifdef RYU_DEBUG
printf("e2=%d\n", e2);
#endif
if (e2 < 0) {
const int32_t idx = -e2 / 16;
#ifdef RYU_DEBUG
printf("idx=%d\n", idx);
#endif
const uint32_t blocks = precision / 9 + 1;
// 0 = don't round up; 1 = round up unconditionally; 2 = round up if odd.
int roundUp = 0;
uint32_t i = 0;
if (blocks <= MIN_BLOCK_2[idx]) {
i = blocks;
memset(result + index, '0', precision);
index += precision;
} else if (i < MIN_BLOCK_2[idx]) {
i = MIN_BLOCK_2[idx];
memset(result + index, '0', 9 * i);
index += 9 * i;
}
for (; i < blocks; ++i) {
const int32_t j = ADDITIONAL_BITS_2 + (-e2 - 16 * idx);
const uint32_t p = POW10_OFFSET_2[idx] + i - MIN_BLOCK_2[idx];
if (p >= POW10_OFFSET_2[idx + 1]) {
// If the remaining digits are all 0, then we might as well use memset.
// No rounding required in this case.
const uint32_t fill = precision - 9 * i;
memset(result + index, '0', fill);
index += fill;
break;
}
// Temporary: j is usually around 128, and by shifting a bit, we push it to 128 or above, which is
// a slightly faster code path in mulShift_mod1e9. Instead, we can just increase the multipliers.
uint32_t digits = mulShift_mod1e9(m2 << 8, POW10_SPLIT_2[p], j + 8);
#ifdef RYU_DEBUG
printf("digits=%u\n", digits);
#endif
if (i < blocks - 1) {
append_nine_digits(digits, result + index);
index += 9;
} else {
const uint32_t maximum = precision - 9 * i;
uint32_t lastDigit = 0;
for (uint32_t k = 0; k < 9 - maximum; ++k) {
lastDigit = digits % 10;
digits /= 10;
}
#ifdef RYU_DEBUG
printf("lastDigit=%u\n", lastDigit);
#endif
if (lastDigit != 5) {
roundUp = lastDigit > 5;
} else {
// Is m * 10^(additionalDigits + 1) / 2^(-e2) integer?
const int32_t requiredTwos = -e2 - (int32_t) precision - 1;
const bool trailingZeros = requiredTwos <= 0
|| (requiredTwos < 60 && multipleOfPowerOf2(m2, (uint32_t) requiredTwos));
roundUp = trailingZeros ? 2 : 1;
#ifdef RYU_DEBUG
printf("requiredTwos=%d\n", requiredTwos);
printf("trailingZeros=%s\n", trailingZeros ? "true" : "false");
#endif
}
if (maximum > 0) {
append_c_digits(maximum, digits, result + index);
index += maximum;
}
break;
}
}
#ifdef RYU_DEBUG
printf("roundUp=%d\n", roundUp);
#endif
if (roundUp != 0) {
int roundIndex = index;
int dotIndex = 0; // '.' can't be located at index 0
while (true) {
--roundIndex;
char c;
if (roundIndex == -1 || (c = result[roundIndex], c == '-')) {
result[roundIndex + 1] = '1';
if (dotIndex > 0) {
result[dotIndex] = '0';
result[dotIndex + 1] = '.';
}
result[index++] = '0';
break;
}
if (c == '.') {
dotIndex = roundIndex;
continue;
} else if (c == '9') {
result[roundIndex] = '0';
roundUp = 1;
continue;
} else {
if (roundUp == 2 && c % 2 == 0) {
break;
}
result[roundIndex] = c + 1;
break;
}
}
}
} else {
memset(result + index, '0', precision);
index += precision;
}
return index;
}
void d2fixed_buffered(double d, uint32_t precision, char* result) {
const int len = d2fixed_buffered_n(d, precision, result);
result[len] = '\0';
}
Ryu_Library/ryu/d2fixed.c view on Meta::CPAN
// a slightly faster code path in mulShift_mod1e9. Instead, we can just increase the multipliers.
digits = (p >= POW10_OFFSET_2[idx + 1]) ? 0 : mulShift_mod1e9(m2 << 8, POW10_SPLIT_2[p], j + 8);
#ifdef RYU_DEBUG
printf("exact=%" PRIu64 " * (%" PRIu64 " + %" PRIu64 " << 64) >> %d\n", m2, POW10_SPLIT_2[p][0], POW10_SPLIT_2[p][1], j);
printf("digits=%u\n", digits);
#endif
if (printedDigits != 0) {
if (printedDigits + 9 > precision) {
availableDigits = 9;
break;
}
append_nine_digits(digits, result + index);
index += 9;
printedDigits += 9;
} else if (digits != 0) {
availableDigits = decimalLength9(digits);
exp = -(i + 1) * 9 + (int32_t) availableDigits - 1;
if (availableDigits > precision) {
break;
}
if (printDecimalPoint) {
append_d_digits(availableDigits, digits, result + index);
index += availableDigits + 1; // +1 for decimal point
} else {
result[index++] = (char) ('0' + digits);
}
printedDigits = availableDigits;
availableDigits = 0;
}
}
}
const uint32_t maximum = precision - printedDigits;
#ifdef RYU_DEBUG
printf("availableDigits=%u\n", availableDigits);
printf("digits=%u\n", digits);
printf("maximum=%u\n", maximum);
#endif
if (availableDigits == 0) {
digits = 0;
}
uint32_t lastDigit = 0;
if (availableDigits > maximum) {
for (uint32_t k = 0; k < availableDigits - maximum; ++k) {
lastDigit = digits % 10;
digits /= 10;
}
}
#ifdef RYU_DEBUG
printf("lastDigit=%u\n", lastDigit);
#endif
// 0 = don't round up; 1 = round up unconditionally; 2 = round up if odd.
int roundUp = 0;
if (lastDigit != 5) {
roundUp = lastDigit > 5;
} else {
// Is m * 2^e2 * 10^(precision + 1 - exp) integer?
// precision was already increased by 1, so we don't need to write + 1 here.
const int32_t rexp = (int32_t) precision - exp;
const int32_t requiredTwos = -e2 - rexp;
bool trailingZeros = requiredTwos <= 0
|| (requiredTwos < 60 && multipleOfPowerOf2(m2, (uint32_t) requiredTwos));
if (rexp < 0) {
const int32_t requiredFives = -rexp;
trailingZeros = trailingZeros && multipleOfPowerOf5(m2, (uint32_t) requiredFives);
}
roundUp = trailingZeros ? 2 : 1;
#ifdef RYU_DEBUG
printf("requiredTwos=%d\n", requiredTwos);
printf("trailingZeros=%s\n", trailingZeros ? "true" : "false");
#endif
}
if (printedDigits != 0) {
if (digits == 0) {
memset(result + index, '0', maximum);
} else {
append_c_digits(maximum, digits, result + index);
}
index += maximum;
} else {
if (printDecimalPoint) {
append_d_digits(maximum, digits, result + index);
index += maximum + 1; // +1 for decimal point
} else {
result[index++] = (char) ('0' + digits);
}
}
#ifdef RYU_DEBUG
printf("roundUp=%d\n", roundUp);
#endif
if (roundUp != 0) {
int roundIndex = index;
while (true) {
--roundIndex;
char c;
if (roundIndex == -1 || (c = result[roundIndex], c == '-')) {
result[roundIndex + 1] = '1';
++exp;
break;
}
if (c == '.') {
continue;
} else if (c == '9') {
result[roundIndex] = '0';
roundUp = 1;
continue;
} else {
if (roundUp == 2 && c % 2 == 0) {
break;
}
result[roundIndex] = c + 1;
break;
}
}
}
result[index++] = 'e';
if (exp < 0) {
result[index++] = '-';
exp = -exp;
} else {
result[index++] = '+';
( run in 1.350 second using v1.01-cache-2.11-cpan-df04353d9ac )