Konwersje liczb

cepa

Na forum jest wiele pytań o konwersje liczb całkowitych i zmienno-przecinkowych do string'ów i na odwrót, najczęstszą odpowiedzią jest użycie funkcji sprintf lecz jest to metoda dość wolna i obchodzi rzeczywisty problem, poniżej jest fragment kodu szerszej biblioteki do obslugi ciągów znaków, który umożliwia konwersje int,float <-> string, kod jest zgodny ze standardem C99, jest tu umieszczony wyłącznie jako przykład. Kod umożliwia także operacje na typach long long (int64_t) oraz long double.

Pełny kod biblioteki (nadal w trakcje rozwoju) pod adresem http://cepa.one.pl/libstr.

We wszystkich funkcjach parametr @base oznacza podstawe systemu liczbowego.

inline int libstr_isbdigit(int c, int base);

Sprawdza czy dany znak należy do systemu liczbowego.

uint32_t libstr_atoul(const char *a, int base);

Konwersja string -> unsigned long.

int32_t libstr_atol(const char *a, int base);

Konwersja string -> long.

uint64_t libstr_atoull(const char *a, int base);

Konwersja string -> unsigned long long.

int64_t libstr_atoll(const char *a, int base);

Konwersja string -> long long.

W poniższych funkcjach wskaznik @a jest wskaznikiem do bufora o wystarczającej dlugosci, w przypadku int32_t jest to 33 bajtów, przy int64_t jest to 65 bajtów.

char *libstr_ultoa(uint32_t x, int base, char *a);

Konwersja unsigned long -> string.

char *libstr_ltoa(int32_t x, int base, char *a);

Konwersja long -> string.

char *libstr_ulltoa(uint64_t x, int base, char *a);

Konwersja unsigned long long -> string.

char *libstr_lltoa(int64_t x, int base, char *a);

Konwersja long long -> string.

double libstr_atod(const char *a);

Konwersja string -> double.

long double libstr_atold(const char *a);

Konwersja string -> long double.

Poniższe funkcje konwertują liczbe zmienno-przecinkową na ciąg cyfr bez kropki dziesiętnej i wykładnika. Są bazą dla właściwych funkcji które wstawiają kropkę, wykładnik znak itd.
Opis:

*ecvt - Zwraca reprezentacje liczby, tak aby było dokładnie @nDigits wszystkich cyfr, jeżeli wymaga to zaokrąglenia to liczba jest zaokrąglana w góre.
*fcvt - Zwraca reprezentacje liczby, tak aby bylo dokładnie @nDigits cyfr po kropce dziesiętnej, jeżeli wymaga to zaokrąglenia to liczba jest zaokrąglana w górę.

Parametry:
@flt - liczba
@nDigits - liczba cyfr (ecvt: wszystkich, fcvt: po przecinku)
@decPoint - pozycja kropki dziesiętnej
@Sign - jezeli 0 to + jak 1 to -
@a - bufor

char *libstr_ecvtbuf(double flt, int nDigits, int *decPoint, int *sign, char *a);

Konwersja double -> string. Używana do konwersji do notacji naukowej.

char *libstr_fcvtbuf(double flt, int nDigits, int *decPoint, int *sign, char *a);

Konwersja double -> string. Używana do konwersji do notacji dziesiętnej.

char *libstr_lecvtbuf(long double flt, int nDigits, int *decPoint, int *sign, char *a);

Konwersja long double -> string. Używana do konwersji do notacji naukowej.

char *libstr_lfcvtbuf(long double flt, int nDigits, int *decPoint, int *sign, char *a);

Konwersja long double -> string. Używana do konwersji do notacji dziesiętnej.

Właściwe konwersje.

/**
 * Enhanced String Library
 * Copyright (c) 2005-2007 Lukasz Cepowski (cepa[at]o2.pl)
 * GNU GPL
 * http://cepa.one.pl/libstr
 */

/*$ libstr_conv.c 2000 2007-03-26 $*/

#include <libstr.h>
#include "libstr_internal.h"
#include <math.h>
#include <float.h>

/**
 * libstr_isbdigit - Return digit value in given numerical system if character
 * is a digit from given numerical system, otherwise -1.
 */
inline int libstr_isbdigit(int c, int base)
{
	c = (unsigned char)c;
	if (c >= '0' && c <= '9') {
		c -= '0';
		if (c < base) return c;
	} else if (c >= 'a' && c <= 'z') {
		c -= 'a';
		base -= 10;
		if (c < base) return c + 10;
	} else if (c >= 'A' && c <= 'Z') {
		c -= 'A';
		base -= 10;
		if (c < base) return c + 10;
	}
	return -1; /* is not */
}

/**
 * libstr_atoul - Convert string to the unsinged 32bit integer value.
 * @base - numerical system (2..36),
 * Function returns numbers between 0 and UINT32_MAX.
 */
uint32_t libstr_atoul(const char *a, int base)
{
	uint32_t result = 0;
	int digit = 0;

	assert(a);

	/* skip whitespaces */
	while (isspace(*a)) a++;

	while (*a) {
		if ((digit = libstr_isbdigit(*a, base)) == -1) break;
		result *= base;
		result += digit;
		a++;
	}
	return result;
}

/**
 * libstr_atol - Convert string to the signed 32bit integer value.
 * @base - numerical system (2..36),
 * Function returns numbers between INT32_MIN and INT32_MAX.
 */
int32_t libstr_atol(const char *a, int base)
{
	int32_t result = 0;
	int digit = 0, isNegative = 0;

	assert(a);

	/* skip whitespaces */
	while (isspace(*a)) a++;

	if (*a == '-') {
		a++;
		isNegative = 1;
	}
	while (*a) {
		if ((digit = libstr_isbdigit(*a, base)) == -1) break;
		result *= base;
		result += digit;
		a++;
	}
	if (isNegative) return -result;
	return result;
}

/**
 * libstr_atoull - Convert string to the unsinged 64bit integer value.
 * @base - numerical system (2..36),
 * Function returns numbers between 0 and UINT64_MAX.
 */
uint64_t libstr_atoull(const char *a, int base)
{
	uint64_t result = 0;
	int digit = 0;

	assert(a);

	/* skip whitespaces */
	while (isspace(*a)) a++;

	while (*a) {
		if ((digit = libstr_isbdigit(*a, base)) == -1) break;
		result *= base;
		result += digit;
		a++;
	}
	return result;
}

/**
 * libstr_atoll - Convert string to the signed 64bit integer value.
 * @base - numerical system (2..36),
 * Function returns numbers between INT64_MIN and INT64_MAX.
 */
int64_t libstr_atoll(const char *a, int base)
{
	int64_t result = 0;
	int digit = 0, isNegative = 0;

	assert(a);

	/* skip whitespaces */
	while (isspace(*a)) a++;

	if (*a == '-') {
		a++;
		isNegative = 1;
	}
	while (*a) {
		if ((digit = libstr_isbdigit(*a, base)) == -1) break;
		result *= base;
		result += digit;
		a++;
	}
	if (isNegative) return -result;
	return result;
}

/**
 * libstr_ultoa - Convert unsigned 32bit integer in given numerical system to the
 * string.
 * @base - numerical system (2..36),
 * @a - pointer to the buffer, minimum size is 33bytes,
 * Return pointer to the string (a) or NULL.
 */
char *libstr_ultoa(uint32_t x, int base, char *a)
{
	int digStack[32], n = 0, m = 0;
	uint32_t y = 0;

	assert(a);

	if (x == 0) {
		a[0] = '0';
		a[1] = '\0';
		return a;
	}

	while (x != 0) {
		y = x;
		x /= base;
		digStack[n++] = (int)(y - x * base);
	}

	while (n--) {
		a[m++] = (digStack[n] < 10 ? digStack[n] + '0' : digStack[n] - 10 + 'a');
	}

	a[m] = '\0';

	return a;
}

/**
 * libstr_ltoa - Convert signed 32bit integer in given numerical system to the
 * string.
 * @base - numerical system (2..36),
 * @a - pointer to the buffer, minimum size is 33bytes,
 * Return pointer to the string (a) or NULL.
 */
char *libstr_ltoa(int32_t x, int base, char *a)
{
	int digStack[32], n = 0, m = 0;
	int32_t y = 0;

	assert(a);

	if (x == 0) {
		a[0] = '0';
		a[1] = '\0';
		return a;
	} else if (x < 0) {
		a[0] = '-';
		m = 1;
	}

	if (x < 0) while (x != 0) {
		y = x;
		x /= base;
		digStack[n++] = -(int)(y - x * base);
	} else while (x != 0) {
		y = x;
		x /= base;
		digStack[n++] = (int)(y - x * base);
	}

	while (n--) {
		a[m++] = (digStack[n] < 10 ? digStack[n] + '0' : digStack[n] - 10 + 'a');
	}

	a[m] = '\0';

	return a;
}

/**
 * libstr_ulltoa - Convert unsigned 64bit integer in given numerical system to the
 * string.
 * @base - numerical system (2..36),
 * @a - pointer to the buffer, minimum size is 65bytes,
 * Return pointer to the string (a) or NULL.
 */
char *libstr_ulltoa(uint64_t x, int base, char *a)
{
	int digStack[64], n = 0, m = 0;
	uint64_t y = 0;

	assert(a);

	if (x == 0) {
		a[0] = '0';
		a[1] = '\0';
		return a;
	}

	while (x != 0) {
		y = x;
		x /= base;
		digStack[n++] = (int)(y - x * base);
	}

	while (n--) {
		a[m++] = (digStack[n] < 10 ? digStack[n] + '0' : digStack[n] - 10 + 'a');
	}

	a[m] = '\0';

	return a;
}

/**
 * libstr_lltoa - Convert signed 64bit integer in given numerical system to the
 * string.
 * @base - numerical system (2..36),
 * @a - pointer to the buffer, minimum size is 65bytes,
 * Return pointer to the string (a) or NULL.
 */
char *libstr_lltoa(int64_t x, int base, char *a)
{
	int digStack[64], n = 0, m = 0;
	int64_t y = 0;

	assert(a);

	if (x == 0) {
		a[0] = '0';
		a[1] = '\0';
		return a;
	} else if (x < 0) {
		a[0] = '-';
		m = 1;
	}

	if (x < 0) while (x != 0) {
		y = x;
		x /= base;
		digStack[n++] = -(int)(y - x * base);
	} else while (x != 0) {
		y = x;
		x /= base;
		digStack[n++] = (int)(y - x * base);
	}

	while (n--) {
		a[m++] = (digStack[n] < 10 ? digStack[n] + '0' : digStack[n] - 10 + 'a');
	}

	a[m] = '\0';

	return a;
}

/**
 * libstr_atod - Convert string to the double.
 */
double libstr_atod(const char *a)
{
	double result = 0.0f, sign = 1.0f;
	int digit = 0, coma = 0, exp = 0, neg = 1;

	assert(a);

	/* skip whitespaces */
	while (isspace(*a)) a++;

	/* get sign */
	switch (*a) {
		case '-': sign = -1.0f;
		case '+': a++;
	}

	/* parse base */
	while ((digit = libstr_isbdigit(*a, 10)) != -1) {
		result *= 10.0f;
		result += (double)digit;
		a++;
	}

	/* parse fraction */
	if (*a == '.') {
		a++;
		while ((digit = libstr_isbdigit(*a, 10)) != -1) {
			result *= 10.0f;
			result += (double)digit;
			a++;
			coma++;
		}
	}

	/* parse exponent */
	if (*a == 'e' || *a == 'E') {
		a++;
		switch (*a) {
			case '-': neg = -1;
			case '+': a++;
		}
		while ((digit = libstr_isbdigit(*a, 10)) != -1) {
			exp *= 10;
			exp += digit;
			a++;
		}
	}

	exp *= neg;
	exp -= coma;

	if (exp > 0) {
		while (exp--)
			result *= 10.0f;
	} else if (exp < 0) {
		while (exp++)
			result /= 10.0f;
	}

	return sign * result;
}

/**
 * libstr_atold - Convert string to the long double.
 */
long double libstr_atold(const char *a)
{
	long double result = 0.0f, sign = 1.0f;
	int digit = 0, coma = 0, exp = 0, neg = 1;

	assert(a);

	/* skip whitespaces */
	while (isspace(*a)) a++;

	/* get sign */
	switch (*a) {
		case '-': sign = -1.0f;
		case '+': a++;
	}

	/* parse base */
	while ((digit = libstr_isbdigit(*a, 10)) != -1) {
		result *= 10.0f;
		result += (long double)digit;
		a++;
	}

	/* parse fraction */
	if (*a == '.') {
		a++;
		while ((digit = libstr_isbdigit(*a, 10)) != -1) {
			result *= 10.0f;
			result += (long double)digit;
			a++;
			coma++;
		}
	}

	/* parse exponent */
	if (*a == 'e' || *a == 'E') {
		a++;
		switch (*a) {
			case '-': neg = -1;
			case '+': a++;
		}
		while ((digit = libstr_isbdigit(*a, 10)) != -1) {
			exp *= 10;
			exp += digit;
			a++;
		}
	}

	exp *= neg;
	exp -= coma;

	if (exp > 0) {
		while (exp--)
			result *= 10.0f;
	} else if (exp < 0) {
		while (exp++)
			result /= 10.0f;
	}

	return sign * result;
}

static int cvt_round_up(char *a, int nDigits)
{
	int rest = 1, i = 0;

	i = nDigits;
	while (i--) {
		a[i] += rest;
		rest = 0;
		if (a[i] > '9') {
			a[i] = '0';
			rest = 1;
		}
	}

	if (rest != 0) {
		a[0] = '1';
		a[nDigits] = '0';
		a[nDigits+1] = '\0';
	}

	return rest;
}

/**
 * libstr_ecvtbuf - Convert double to string.
 * @x - double float variable,
 * @nDigits - count of returned digits,
 * @decPoint - pointer to variable with position of decimal point,
 * @sign - pointer to variable with sign (+ => 0, - => 1),
 * @a - buffer,
 *
 * Size of the buffer should be enough to store all bytes from conversion.
 * The value of double is between 2,2E-308 and 1,8E+308 so
 * DBL_MAX_10_EXP + 2 bytes are enough.
 * Sometimes value is rouned up if given n-digits variable is less than
 * nominal size of converted string.
 * Function returns a pointer to the @a, count of used bytes is always equal
 * to @nDigits.
 */
char *libstr_ecvtbuf(double flt, int nDigits, int *decPoint, int *sign, char *a)
{
	int exp = 0, digit = 0, i = 0;

	assert(a);
	assert(nDigits <= DBL_MAX_10_EXP); /* 308 */

	/* get sign */
	if (flt < 0.0f && sign) *sign = 1;
	else if (sign) *sign = 0;

	/* abs */
	flt = fabs(flt);

	/* get exponent */
	exp = (int)log10(flt);

	/* normalize */
	flt /= pow(10.0f, exp);
	if (flt < 1.0f) {
		flt *= 10.0f;
		exp--;
	}

	/* conversion */
	for (i = 0; i < nDigits; i++) {
		flt = flt - (double)digit * 10.0f;
		digit = (int)flt;
		flt *= 10.0f;
		a[i] = digit + '0';
	}
	digit = (int)(flt - (double)digit * 10.0f);
	a[i] = '\0';

	/* round up if neccessary */
	i = 0;
	if (digit >= 5)
		i = cvt_round_up(a, nDigits);

	/* get decimal point */
	if (decPoint)
		*decPoint = exp + 1 + i;

	return a;
}

/**
 * libstr_fcvtbuf - Convert double to string.
 * @x - double float variable,
 * @nDigits - count of returned digits AFTER DECIMAL POINT(!),
 * @decPoint - pointer to variable with position of decimal point,
 * @sign - pointer to variable with sign (+ => 0, - => 1),
 * @a - buffer,
 *
 * Size of the buffer should be enough to store all bytes from conversion.
 * The value of double is between 2,2E-308 and 1,8E+308 so
 * 2 * DBL_MAX_10_EXP + 2 bytes are enough.
 * Sometimes value is rouned up if given n-digits variable is less than
 * nominal size of converted string.
 * Function returns a pointer to the @a. Returned string contains whole integer
 * value (base) and fraction with given count of digits (@nDigits).
 */
char *libstr_fcvtbuf(double flt, int nDigits, int *decPoint, int *sign, char *a)
{
	int exp = 0, digit = 0, i = 0;

	assert(a);
	assert(nDigits <= DBL_MAX_10_EXP); /* 308 */

	/* get sign */
	if (flt < 0.0f && sign) *sign = 1;
	else if (sign) *sign = 0;

	/* abs */
	flt = fabs(flt);

	/* get exponent */
	exp = (int)log10(flt);
	if (flt >= 1.0f) nDigits += exp+1;

	/* normalize */
	flt /= pow(10.0f, exp);
	if (flt < 1.0f) {
		flt *= 10.0f;
		exp--;
	}

	/* conversion */
	for (i = 0; i < nDigits; i++) {
		flt = flt - (double)digit * 10.0f;
		digit = (int)flt;
		flt *= 10.0f;
		a[i] = digit + '0';
	}
	digit = (int)(flt - (double)digit * 10.0f);
	a[i] = '\0';

	/* round up if neccessary */
	i = 0;
	if (digit >= 5)
		i = cvt_round_up(a, nDigits);

	/* get decimal point */
	if (decPoint)
		*decPoint = exp + 1 + i;

	return a;
}

/**
 * libstr_lecvtbuf - Convert long double to string.
 * @x - long double float variable,
 * @nDigits - count of returned digits,
 * @decPoint - pointer to variable with position of decimal point,
 * @sign - pointer to variable with sign (+ => 0, - => 1),
 * @a - buffer,
 *
 * Size of the buffer should be enough to store all bytes from conversion.
 * The value of long double is between so 3,4E-4932 ÷ 1,2E+4932 so
 * LDBL_MAX_10_EXP + 2 bytes are enough.
 * Sometimes value is rouned up if given n-digits variable is less than
 * nominal size of converted string.
 * Function returns a pointer to the @a, count of used bytes is always equal
 * to @nDigits.
 */
char *libstr_lecvtbuf(long double flt, int nDigits, int *decPoint, int *sign, char *a)
{
	int exp = 0, digit = 0, i = 0;

	assert(a);
	assert(nDigits <= LDBL_MAX_10_EXP); /* 308 */

	/* get sign */
	if (flt < 0.0f && sign) *sign = 1;
	else if (sign) *sign = 0;

	/* abs */
	flt = fabsl(flt);

	/* get exponent */
	exp = (int)log10l(flt);

	/* normalize */
	flt /= powl(10.0f, exp);
	if (flt < 1.0f) {
		flt *= 10.0f;
		exp--;
	}

	/* conversion */
	for (i = 0; i < nDigits; i++) {
		flt = flt - (long double)digit * 10.0f;
		digit = (int)flt;
		flt *= 10.0f;
		a[i] = digit + '0';
	}
	digit = (int)(flt - (long double)digit * 10.0f);
	a[i] = '\0';

	/* round up if neccessary */
	i = 0;
	if (digit >= 5)
		i = cvt_round_up(a, nDigits);

	/* get decimal point */
	if (decPoint)
		*decPoint = exp + 1 + i;

	return a;
}

/**
 * libstr_lfcvtbuf - Convert long double to string.
 * @x - long double float variable,
 * @nDigits - count of returned digits AFTER DECIMAL POINT(!),
 * @decPoint - pointer to variable with position of decimal point,
 * @sign - pointer to variable with sign (+ => 0, - => 1),
 * @a - buffer,
 *
 * Size of the buffer should be enough to store all bytes from conversion.
 * The value of long double is between 3,4E-4932 ÷ 1,2E+4932 so
 * 2 * LDBL_MAX_10_EXP + 2 bytes are enough.
 * Sometimes value is rouned up if given n-digits variable is less than
 * nominal size of converted string.
 * Function returns a pointer to the @a. Returned string contains whole integer
 * value (base) and fraction with given count of digits (@nDigits).
 */
char *libstr_lfcvtbuf(long double flt, int nDigits, int *decPoint, int *sign, char *a)
{
	int exp = 0, digit = 0, i = 0;

	assert(a);
	assert(nDigits <= LDBL_MAX_10_EXP); /* 308 */

	/* get sign */
	if (flt < 0.0f && sign) *sign = 1;
	else if (sign) *sign = 0;

	/* abs */
	flt = fabsl(flt);

	/* get exponent */
	exp = (int)log10l(flt);
	if (flt >= 1.0f) nDigits += exp+1;

	/* normalize */
	flt /= powl(10.0f, exp);
	if (flt < 1.0f) {
		flt *= 10.0f;
		exp--;
	}

	/* conversion */
	for (i = 0; i < nDigits; i++) {
		flt = flt - (double)digit * 10.0f;
		digit = (int)flt;
		flt *= 10.0f;
		a[i] = digit + '0';
	}
	digit = (int)(flt - (double)digit * 10.0f);
	a[i] = '\0';

	/* round up if neccessary */
	i = 0;
	if (digit >= 5)
		i = cvt_round_up(a, nDigits);

	/* get decimal point */
	if (decPoint)
		*decPoint = exp + 1 + i;

	return a;
}

Przykłady użycia (zwłaszcza float itp).

/**
 * Enhanced String Library
 * Copyright (c) 2005-2007 Lukasz Cepowski (cepa[at]o2.pl)
 * GNU GPL
 * http://cepa.one.pl/libstr
 */

/*$ str_conv.c 2000 2007-03-26 $*/

#include <libstr.h>
#include "libstr_internal.h"
#include <float.h>

/**
 * str_atoul - String to unsigned 32bit integer.
 */
uint32_t str_atoul(const String *str, int base)
{
	assert(str);
	return libstr_atoul(str->data, base);
}

/**
 * str_atol - String to signed 32bit integer.
 */
int32_t str_atol(const String *str, int base)
{
	assert(str);
	return libstr_atol(str->data, base);
}

/**
 * str_atoull - String to unsigned 64bit integer.
 */
uint64_t str_atoull(const String *str, int base)
{
	assert(str);
	return libstr_atoull(str->data, base);
}

/**
 * str_atoll - String to signed 64bit integer.
 */
int64_t str_atoll(const String *str, int base)
{
	assert(str);
	return libstr_atoll(str->data, base);
}

/**
 * str_ultoa - Unsigned 32bit integer to string.
 */
String *str_ultoa(uint32_t x, int base, String *str)
{
	if (!str) str = str_new_block(33);
	else str = str_realloc(str, 33);
	if (!str) return NULL;
	libstr_ultoa(x, base, str->data);
	str = str_align_null(str);
	return str;
}

/**
 * str_ltoa - Signed 32bit integer to string.
 */
String *str_ltoa(int32_t x, int base, String *str)
{
	if (!str) str = str_new_block(33);
	else str = str_realloc(str, 33);
	if (!str) return NULL;
	libstr_ltoa(x, base, str->data);
	str = str_align_null(str);
	return str;
}

/**
 * str_ulltoa - Unsigned 64bit integer to string.
 */
String *str_ulltoa(uint64_t x, int base, String *str)
{
	if (!str) str = str_new_block(65);
	else str = str_realloc(str, 65);
	if (!str) return NULL;
	libstr_ulltoa(x, base, str->data);
	str = str_align_null(str);
	return str;
}

/**
 * str_lltoa - Signed 64bit integer to string.
 */
String *str_lltoa(int64_t x, int base, String *str)
{
	if (!str) str = str_new_block(65);
	else str = str_realloc(str, 65);
	if (!str) return NULL;
	libstr_lltoa(x, base, str->data);
	str = str_align_null(str);
	return str;
}

/**
 * str_atod - Convert string to double.
 */
double str_atod(const String *str)
{
	assert(str);
	return libstr_atod(str->data);
}

/**
 * str_atold - Convert string to long double.
 */
long double str_atold(const String *str)
{
	assert(str);
	return libstr_atold(str->data);
}

/**
 * str_dtoa - Convert double to string (Floating notation).
 */
String *str_dtoa(double x, int nDigits, String *str)
{
	int decPt = 0, sign = 0;

	if (!str) str = str_new_block(2 * DBL_MAX_10_EXP + 20);
	else str = str_realloc(str, 2 * DBL_MAX_10_EXP + 20);
	if (!str) return NULL;

	libstr_fcvtbuf(x, nDigits, &decPt, &sign, str->data);
	str = str_align_null(str);

	if (decPt > 0) {
		str = str_insert_ch(str, '.', decPt);
	} else {
		str = str_repeat_ch(str, '0', 0, -decPt + 1);
		str = str_insert_ch(str, '.', 1);
	}

	if (sign == 1) {
		str = str_prepend_ch(str, '-');
	}

	return str;
}

/**
 * str_dtoae - Convert double to string (Scientific notation).
 */
String *str_dtoae(double x, int nDigits, String *str)
{
	int decPt = 0, sign = 0;
	char buf[10];

	if (!str) str = str_new_block(DBL_MAX_10_EXP + 20);
	else str = str_realloc(str, DBL_MAX_10_EXP + 20);
	if (!str) return NULL;

	libstr_ecvtbuf(x, nDigits, &decPt, &sign, str->data);
	str = str_align_null(str);

	if (decPt > 0) {
		if (decPt > str->strLen) {
			/* scientific notation */
			if (str->strLen > 1) str = str_insert_ch(str, '.', 1);
			libstr_ltoa(decPt-1, 10, buf);
			str = str_append_ch(str, 'e');
			str = str_append_cstr(str, buf);
		} else if (decPt < str->strLen) {
			str = str_insert_ch(str, '.', decPt);
		}
	} else {
		/* scientific notation */
		libstr_ltoa(decPt-1, 10, buf);
		str = str_insert_ch(str, '.', 1);
		str = str_append_ch(str, 'e');
		str = str_append_cstr(str, buf);
	}

	if (sign == 1) {
		str = str_prepend_ch(str, '-');
	}

	return str;
}

/**
 * str_ldtoa - Convert long double to string (Floating notation).
 */
String *str_ldtoa(long double x, int nDigits, String *str)
{
	int decPt = 0, sign = 0;

	if (!str) str = str_new_block(2 * LDBL_MAX_10_EXP + 20);
	else str = str_realloc(str, 2 * LDBL_MAX_10_EXP + 20);
	if (!str) return NULL;

	libstr_lfcvtbuf(x, nDigits, &decPt, &sign, str->data);
	str = str_align_null(str);

	if (decPt > 0) {
		str = str_insert_ch(str, '.', decPt);
	} else {
		str = str_repeat_ch(str, '0', 0, -decPt + 1);
		str = str_insert_ch(str, '.', 1);
	}

	if (sign == 1) {
		str = str_prepend_ch(str, '-');
	}

	return str;
}

/**
 * str_ldtoae - Convert long double to string (Scientific notation).
 */
String *str_ldtoae(long double x, int nDigits, String *str)
{
	int decPt = 0, sign = 0;
	char buf[10];

	if (!str) str = str_new_block(LDBL_MAX_10_EXP + 20);
	else str = str_realloc(str, LDBL_MAX_10_EXP + 20);
	if (!str) return NULL;

	libstr_lecvtbuf(x, nDigits, &decPt, &sign, str->data);
	str = str_align_null(str);

	if (decPt > 0) {
		if (decPt > str->strLen) {
			/* scientific notation */
			if (str->strLen > 1) str = str_insert_ch(str, '.', 1);
			libstr_ltoa(decPt-1, 10, buf);
			str = str_append_ch(str, 'e');
			str = str_append_cstr(str, buf);
		} else if (decPt < str->strLen) {
			str = str_insert_ch(str, '.', decPt);
		}
	} else {
		/* scientific notation */
		libstr_ltoa(decPt-1, 10, buf);
		str = str_insert_ch(str, '.', 1);
		str = str_append_ch(str, 'e');
		str = str_append_cstr(str, buf);
	}

	if (sign == 1) {
		str = str_prepend_ch(str, '-');
	}

	return str;
}

2 komentarzy

Naprawde dobry kod, przyda się :) gratulacje i pzdr

Naprawdę fajne :)