StrFromF64
Description
Convert a double to string
Parameters
| Name | Direction | Description |
|---|---|---|
str |
out | String to store the result in |
value |
in | Value to convert |
config |
in | Formatting configuration. May be NULL (uses the default: 6 decimal places). |
Success
Returns str
Failure
Returns NULL on allocator OOM while appending to str, or when a non-NULL config has an invalid precision (> 17). The destination string is untouched.
Usage example (Cross-references)
Usage examples (Cross-references)
- In
Io.c:2201:
// covers it with margin. No allocator -- `o` may be a stack Str.
StrInitStack(temp, 1024) {
if (!StrFromF64(&temp, *v, &config)) {
return false;
}- In
Str.c:660:
}
Str *StrFromF64(Str *str, f64 value, const StrFloatFormat *config) {
ValidateStr(str);- In
Convert.c:156:
// Test StrFromF64 function
bool test_str_from_f64(void) {
WriteFmt("Testing StrFromF64\n");
DefaultAllocator alloc = DefaultAllocatorInit();- In
Convert.c:164:
// Test integer conversion
StrFloatFormat config = {.precision = 2, .force_sci = false, .uppercase = false};
StrFromF64(&s, 123.0, &config);
bool result = (ZstrCompare(StrBegin(&s), "123.00") == 0);
if (!result) {- In
Convert.c:173:
StrClear(&s);
config = (StrFloatFormat) {.precision = 3, .force_sci = false, .uppercase = false};
StrFromF64(&s, 123.456, &config);
result = result && (ZstrCompare(StrBegin(&s), "123.456") == 0);
if (!result) {- In
Convert.c:182:
StrClear(&s);
config = (StrFloatFormat) {.precision = 3, .force_sci = false, .uppercase = false};
StrFromF64(&s, -123.456, &config);
result = result && (ZstrCompare(StrBegin(&s), "-123.456") == 0);- In
Convert.c:188:
StrClear(&s);
config = (StrFloatFormat) {.precision = 3, .force_sci = true, .uppercase = false};
StrFromF64(&s, 123.456, &config);
result = result && (ZstrCompare(StrBegin(&s), "1.235e+02") == 0);- In
Convert.c:194:
StrClear(&s);
config = (StrFloatFormat) {.precision = 3, .force_sci = true, .uppercase = true};
StrFromF64(&s, 123.456, &config);
result = result && (ZstrCompare(StrBegin(&s), "1.235E+02") == 0);- In
Convert.c:200:
StrClear(&s);
config = (StrFloatFormat) {.precision = 3, .force_sci = false, .uppercase = false};
StrFromF64(&s, 0.0000123, &config);
result = result && (ZstrCompare(StrBegin(&s), "1.230e-05") == 0);- In
Convert.c:206:
StrClear(&s);
config = (StrFloatFormat) {.precision = 2, .force_sci = false, .uppercase = false};
StrFromF64(&s, 1234567890123.0, &config);
result = result && (ZstrCompare(StrBegin(&s), "1.23e+12") == 0);- In
Convert.c:212:
StrClear(&s);
config = (StrFloatFormat) {.precision = 2, .force_sci = false, .uppercase = false};
StrFromF64(&s, 0.0, &config);
result = result && (ZstrCompare(StrBegin(&s), "0.00") == 0);- In
Convert.c:218:
StrClear(&s);
config = (StrFloatFormat) {.precision = 2, .force_sci = false, .uppercase = false};
StrFromF64(&s, F64_INFINITY, &config);
result = result && (ZstrCompare(StrBegin(&s), "inf") == 0);- In
Convert.c:224:
StrClear(&s);
config = (StrFloatFormat) {.precision = 2, .force_sci = false, .uppercase = false};
StrFromF64(&s, -F64_INFINITY, &config);
result = result && (ZstrCompare(StrBegin(&s), "-inf") == 0);- In
Convert.c:230:
StrClear(&s);
config = (StrFloatFormat) {.precision = 2, .force_sci = false, .uppercase = false};
StrFromF64(&s, F64_NAN, &config);
result = result && (ZstrCompare(StrBegin(&s), "nan") == 0);- In
Convert.c:476:
StrFloatFormat config = {.precision = precision, .force_sci = false, .uppercase = false};
StrFromF64(&s, f64_values[i], &config);
f64 recovered_f64 = 0.0;
bool success = StrToF64(&s, &recovered_f64, NULL);- In
Convert.c:538:
StrClear(&s);
StrFloatFormat fconfig = {.precision = 3, .force_sci = false, .uppercase = false};
StrFromF64(&s, 1e-300, &fconfig);
f64 recovered_small = 0.0;
success = StrToF64(&s, &recovered_small, NULL);- In
Convert.c:546:
StrClear(&s);
fconfig = (StrFloatFormat) {.precision = 3, .force_sci = false, .uppercase = false};
StrFromF64(&s, 1e300, &fconfig);
f64 recovered_large = 0.0;
success = StrToF64(&s, &recovered_large, NULL);- In
Convert.c:595:
StrFloatFormat config = {.precision = precision, .force_sci = false, .uppercase = false};
StrFromF64(&s, test_value, &config);
// String should have expected decimal places
- In
Convert.c:616:
// Force scientific notation
StrFloatFormat config = {.precision = 3, .force_sci = true, .uppercase = false};
StrFromF64(&s, sci_values[i], &config);
bool has_e = (ZstrFindChar(StrBegin(&s), 'e') != NULL);
result = result && has_e;- In
Convert.c:623:
StrClear(&s);
config = (StrFloatFormat) {.precision = 3, .force_sci = true, .uppercase = true};
StrFromF64(&s, sci_values[i], &config);
bool has_E = (ZstrFindChar(StrBegin(&s), 'E') != NULL);
result = result && has_E;- In
Convert.c:756:
Str s = StrInit(&alloc);
StrFloatFormat config = {.precision = 6, .force_sci = false, .uppercase = false};
StrFromF64(&s, test_value, &config);
f64 recovered = 0.0;- In
Convert.c:819:
// Test StrFromF64 with NULL pointer - should abort
StrFloatFormat config = {.precision = 2, .force_sci = false, .uppercase = false};
StrFromF64(NULL, 123.45, &config);
return false;- In
Convert.c:1322:
// 4-byte "nan\0" instead of the 3-byte "nan".
static bool test_nan_length_and_bytes(void) {
WriteFmt("Testing StrFromF64 NaN emits exactly 3 bytes\n");
DefaultAllocator alloc = DefaultAllocatorInit();
Str s = StrInit(&alloc);- In
Convert.c:1327:
StrFloatFormat config = {.precision = 2, .force_sci = false, .uppercase = false};
StrFromF64(&s, F64_NAN, &config);
bool result = (StrLen(&s) == 3) && (ZstrCompare(StrBegin(&s), "nan") == 0);- In
Convert.c:1341:
// pushes it, giving 4-byte "inf\0" instead of 3-byte "inf".
static bool test_inf_length_and_bytes(void) {
WriteFmt("Testing StrFromF64 inf emits exactly 3 bytes\n");
DefaultAllocator alloc = DefaultAllocatorInit();
Str s = StrInit(&alloc);- In
Convert.c:1346:
StrFloatFormat config = {.precision = 2, .force_sci = false, .uppercase = false};
StrFromF64(&s, F64_INFINITY, &config);
bool result = (StrLen(&s) == 3) && (ZstrCompare(StrBegin(&s), "inf") == 0);- In
Convert.c:1361:
// fixed notation ("0.000100") to scientific ("1.000000e-04").
static bool test_small_threshold_stays_fixed(void) {
WriteFmt("Testing StrFromF64 0.0001 stays fixed notation\n");
DefaultAllocator alloc = DefaultAllocatorInit();
Str s = StrInit(&alloc);- In
Convert.c:1366:
StrFloatFormat config = {.precision = 6, .force_sci = false, .uppercase = false};
StrFromF64(&s, 0.0001, &config);
bool result = (ZstrCompare(StrBegin(&s), "0.000100") == 0);- In
Convert.c:1381:
// of scientific ("1.00e+07").
static bool test_large_threshold_uses_sci(void) {
WriteFmt("Testing StrFromF64 1e7 uses scientific notation\n");
DefaultAllocator alloc = DefaultAllocatorInit();
Str s = StrInit(&alloc);- In
Convert.c:1386:
StrFloatFormat config = {.precision = 2, .force_sci = false, .uppercase = false};
StrFromF64(&s, 1e7, &config);
bool result = (ZstrCompare(StrBegin(&s), "1.00e+07") == 0);- In
Convert.c:1401:
// zero-iteration fraction loop, giving "5.e+00" instead of "5e+00".
static bool test_sci_precision_zero_no_dot(void) {
WriteFmt("Testing StrFromF64 scientific precision 0 omits dot\n");
DefaultAllocator alloc = DefaultAllocatorInit();
Str s = StrInit(&alloc);- In
Convert.c:1406:
StrFloatFormat config = {.precision = 0, .force_sci = true, .uppercase = false};
StrFromF64(&s, 5.0, &config);
bool result = (ZstrCompare(StrBegin(&s), "5e+00") == 0);- In
Convert.c:1420:
// the else branch: emits '-' and "00", giving "5.00e-00" instead of "5.00e+00".
static bool test_sci_zero_exponent_sign(void) {
WriteFmt("Testing StrFromF64 zero exponent prints +00\n");
DefaultAllocator alloc = DefaultAllocatorInit();
Str s = StrInit(&alloc);- In
Convert.c:1425:
StrFloatFormat config = {.precision = 2, .force_sci = true, .uppercase = false};
StrFromF64(&s, 5.0, &config);
bool result = (ZstrCompare(StrBegin(&s), "5.00e+00") == 0);- In
Convert.c:1441:
// must return the destination handle, not NULL.
static bool test_sci_exponent_success_returns_handle(void) {
WriteFmt("Testing StrFromF64 scientific success returns handle\n");
DefaultAllocator alloc = DefaultAllocatorInit();
Str s = StrInit(&alloc);- In
Convert.c:1446:
StrFloatFormat config = {.precision = 2, .force_sci = true, .uppercase = false};
Str *r = StrFromF64(&s, 123.456, &config);
bool result = (r == &s) && (ZstrCompare(StrBegin(&s), "1.23e+02") == 0);- In
Convert.c:1461:
// successful call must return the destination handle.
static bool test_fixed_integer_success_returns_handle(void) {
WriteFmt("Testing StrFromF64 fixed success returns handle\n");
DefaultAllocator alloc = DefaultAllocatorInit();
Str s = StrInit(&alloc);- In
Convert.c:1466:
StrFloatFormat config = {.precision = 2, .force_sci = false, .uppercase = false};
Str *r = StrFromF64(&s, 123.0, &config);
bool result = (r == &s) && (ZstrCompare(StrBegin(&s), "123.00") == 0);- In
Convert.c:1481:
// zero-iteration fraction loop, giving "123." instead of "123".
static bool test_fixed_precision_zero_no_dot(void) {
WriteFmt("Testing StrFromF64 fixed precision 0 omits dot\n");
DefaultAllocator alloc = DefaultAllocatorInit();
Str s = StrInit(&alloc);- In
Convert.c:1486:
StrFloatFormat config = {.precision = 0, .force_sci = false, .uppercase = false};
StrFromF64(&s, 123.0, &config);
bool result = (ZstrCompare(StrBegin(&s), "123") == 0);- In
Convert.c:1501:
// the fractional digits become garbage instead of "456".
static bool test_fixed_fraction_scale_seed(void) {
WriteFmt("Testing StrFromF64 fixed fraction scale seed\n");
DefaultAllocator alloc = DefaultAllocatorInit();
Str s = StrInit(&alloc);- In
Convert.c:1506:
StrFloatFormat config = {.precision = 3, .force_sci = false, .uppercase = false};
StrFromF64(&s, 123.456, &config);
bool result = (ZstrCompare(StrBegin(&s), "123.456") == 0);- In
Convert.c:1522:
// raw value and emits "0.123".
static bool test_fixed_round_half_up(void) {
WriteFmt("Testing StrFromF64 fixed half-up rounding\n");
DefaultAllocator alloc = DefaultAllocatorInit();
Str s = StrInit(&alloc);- In
Convert.c:1527:
StrFloatFormat config = {.precision = 3, .force_sci = false, .uppercase = false};
StrFromF64(&s, 0.1235, &config);
bool result = (ZstrCompare(StrBegin(&s), "0.124") == 0);- In
Convert.c:1541:
// past the fail-fast barrier. Deadend: a NULL str must abort.
static bool test_from_f64_null_aborts(void) {
WriteFmt("Testing StrFromF64 NULL aborts\n");
StrFloatFormat config = {.precision = 2, .force_sci = false, .uppercase = false};
StrFromF64(NULL, 1.0, &config);- In
Convert.c:1543:
WriteFmt("Testing StrFromF64 NULL aborts\n");
StrFloatFormat config = {.precision = 2, .force_sci = false, .uppercase = false};
StrFromF64(NULL, 1.0, &config);
return false;
}- In
Convert.c:1548:
static bool test_from_f64_null_aborts_high_precision(void) {
WriteFmt("Testing StrFromF64 NULL aborts before the precision guard\n");
StrFloatFormat config = {.precision = 18, .force_sci = false, .uppercase = false};
StrFromF64(NULL, 1.0, &config);- In
Convert.c:1550:
WriteFmt("Testing StrFromF64 NULL aborts before the precision guard\n");
StrFloatFormat config = {.precision = 18, .force_sci = false, .uppercase = false};
StrFromF64(NULL, 1.0, &config);
return false;
}- In
Convert.c:1881:
// truncates to "2.2".
static bool test_round_f64_guard_first_term(void) {
WriteFmt("Testing StrFromF64 rounds 2.25@p1 to 2.3 (round_f64 guard, first term)\n");
DefaultAllocator alloc = DefaultAllocatorInit();- In
Convert.c:1886:
Str s = StrInit(&alloc);
StrFloatFormat config = {.precision = 1, .force_sci = false, .uppercase = false};
StrFromF64(&s, 2.25, &config);
bool result = (ZstrCompare(StrBegin(&s), "2.3") == 0);
if (!result) {- In
Convert.c:1901:
// is skipped and 2.25@p1 prints "2.2" instead of "2.3".
static bool test_round_f64_guard_second_term(void) {
WriteFmt("Testing StrFromF64 rounds 2.25@p1 to 2.3 (round_f64 guard, second term)\n");
DefaultAllocator alloc = DefaultAllocatorInit();- In
Convert.c:1906:
Str s = StrInit(&alloc);
StrFloatFormat config = {.precision = 1, .force_sci = false, .uppercase = false};
StrFromF64(&s, 2.25, &config);
bool result = (ZstrCompare(StrBegin(&s), "2.3") == 0);
if (!result) {- In
Convert.c:2009:
// mutant : `ok` becomes truthy -> falls through -> returns &s (non-NULL).
static bool test_from_f64_int_oom_returns_null(void) {
WriteFmt("Testing StrFromF64 returns NULL when an integer-digit push fails (817:28)\n");
u8 buf[64] = {0};- In
Convert.c:2022:
// push needs a 9-byte buffer and fails inside the integer-digit loop. No
// later direct-return push can mask the mutated `ok`.
Str *ret = StrFromF64(&s, 123456789012345.0, &config);
bool result = (ret == NULL);- In
Convert.c:2051:
// mutant : `ok` becomes truthy -> falls through -> returns &s (non-NULL).
static bool test_from_f64_exp_oom_returns_null(void) {
WriteFmt("Testing StrFromF64 returns NULL when an exponent-digit push fails (790:28)\n");
u8 buf[512] = {0};- In
Convert.c:2058:
Str s = StrInit(&bp);
StrFloatFormat config = {.precision = 2, .force_sci = true, .uppercase = false};
Str *ret = StrFromF64(&s, 1.23e150, &config);
bool result = (ret == NULL);- In
Convert.c:2216:
test_validate_str_guard, // StrToF64 (Str.Mutants1)
test_str_to_u64_validate_barrier, // StrToU64 (Str.Mutants2)
test_from_f64_null_aborts, // StrFromF64 (Str.Mutants3)
test_from_f64_null_aborts_high_precision,
test_str_to_i64_corrupt_str_aborts // StrToI64 (Str.Mutants5)
Last updated on