Skip to content

Instantly share code, notes, and snippets.

@jonas-s-s-s
Created December 4, 2024 11:37
Show Gist options
  • Save jonas-s-s-s/9974a79ce7d9b7e7ac1b51f9ea4e1de8 to your computer and use it in GitHub Desktop.
Save jonas-s-s-s/9974a79ce7d9b7e7ac1b51f9ea4e1de8 to your computer and use it in GitHub Desktop.
dtoa / double to string
// Logic form: http://git.musl-libc.org/cgit/musl/tree/src/stdio/vfprintf.c#n208
// Example program
#include <cstdio>
#include <math.h>
#include <limits.h>
#define MAX(a, b) ((a) > (b) ? (a) : (b))
#define MIN(a, b) ((a) < (b) ? (a) : (b))
#define DEFAULT_PRECISION 6 // Default precision for floating-point conversion
// Helper to check if a number is NaN or Infinity
static const char *check_special_cases(double num) {
if (isnan(num)) return "nan";
if (isinf(num)) return (num < 0) ? "-inf" : "inf";
return NULL;
}
// Helper to reverse a string in place
static void reverse_str(char *str, int len) {
int i, j;
char temp;
for (i = 0, j = len - 1; i < j; i++, j--) {
temp = str[i];
str[i] = str[j];
str[j] = temp;
}
}
// Helper to convert an integer to string
static int int_to_str(int num, char *str, int min_width) {
int i = 0;
int is_negative = (num < 0);
if (is_negative) num = -num;
do {
str[i++] = '0' + (num % 10);
num /= 10;
} while (num > 0);
if (is_negative) str[i++] = '-';
// Pad with zeros if necessary
while (i < min_width) str[i++] = '0';
str[i] = '\0';
reverse_str(str, i);
return i;
}
// Core function to convert double to string
void fmt_fp_to_str(double num, char *buf, int precision, char format) {
char temp[32]; // Temporary buffer for intermediate results
int temp_len;
int int_part;
double frac_part;
int frac_len = 0;
int i = 0, j;
const char *special_case;
// Handle special cases (NaN, Infinity)
special_case = check_special_cases(num);
if (special_case) {
while (*special_case) buf[i++] = *special_case++;
buf[i] = '\0';
return;
}
// Handle negative numbers
if (num < 0) {
buf[i++] = '-';
num = -num;
}
// Default precision
if (precision < 0) precision = DEFAULT_PRECISION;
// Extract integer and fractional parts
int_part = (int)num;
frac_part = num - int_part;
// Convert integer part to string
temp_len = int_to_str(int_part, temp, 0);
for (j = 0; j < temp_len; j++) buf[i++] = temp[j];
// Handle fractional part
if (precision > 0) {
buf[i++] = '.'; // Decimal point
while (precision-- > 0) {
frac_part *= 10;
int digit = (int)frac_part;
buf[i++] = '0' + digit;
frac_part -= digit;
}
// Simple rounding: check if remaining fraction >= 0.5
if (frac_part >= 0.5) {
j = i - 1;
while (j >= 0 && buf[j] == '9') {
buf[j] = '0';
j--;
}
if (j >= 0 && buf[j] != '.') {
buf[j]++;
} else if (j < 0 || buf[j] == '.') {
// If overflow affects the integer part, insert '1' at the start
for (j = i; j > 0; j--) buf[j] = buf[j - 1];
buf[0] = '1';
i++;
}
}
}
// Null-terminate the string
buf[i] = '\0';
// Handle scientific/exponential notation if specified
if (format == 'e' || format == 'E') {
int exponent = 0;
char sign;
// Normalize the number to 1.xxxxx * 10^exponent
while (num >= 10.0) {
num /= 10.0;
exponent++;
}
while (num > 0.0 && num < 1.0) {
num *= 10.0;
exponent--;
}
// Rebuild the string in scientific format
i = 0;
fmt_fp_to_str(num, buf, precision, '\0'); // Reuse this function for normalized number
while (buf[i]) i++; // Move to the end of the number
buf[i++] = (format == 'e') ? 'e' : 'E'; // Append 'e' or 'E'
sign = (exponent < 0) ? '-' : '+';
buf[i++] = sign;
// Append the exponent
if (exponent < 0) exponent = -exponent;
temp_len = int_to_str(exponent, temp, 2); // At least 2 digits for exponent
for (j = 0; j < temp_len; j++) buf[i++] = temp[j];
buf[i] = '\0'; // Null-terminate
}
}
int main() {
char buffer[128];
fmt_fp_to_str(1234.56789, buffer, 8, 'f'); // Fixed-point
printf("Fixed-point: %s\n", buffer);
fmt_fp_to_str(-0.000123456, buffer, 5, 'e'); // Scientific notation
printf("Scientific: %s\n", buffer);
fmt_fp_to_str(0.0 / 0.0, buffer, 6, 'f'); // NaN
printf("NaN: %s\n", buffer);
fmt_fp_to_str(1.0 / 0.0, buffer, 6, 'f'); // Infinity
printf("Infinity: %s\n", buffer);
return 0;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment