LINUX.ORG.RU

Есть ли «честный» аналог функции strtod?


0

0

Я пытаюсь получить число double из введенной пользователем (или считанной из файла) строки при помощи strtod(str, &ptr), где str - указатель на строку с числом, ptr - указатель на неиспользуемый остаток строки.

Все время точность полученного числа не превышает шести символов! Даже если введено число с 10-ю символами после запятой. При этом ptr указывает на конец строки, т.е. все число из str было «конвертировано».

atof является синонимом strtod(str, NULL), т.е. ведет себя абсолютно так же криво.

Какую функцию можно использовать, чтобы преобразовать строку в double?

☆☆☆☆☆

Покажи тесткейс где такое происходит. Типа вот такого:

#include <stdlib.h>
#include <stdio.h>

int main () {

    char *num = "1.324486723956792";

    double v = strtod(num, NULL);

    printf("v=%.16f\n", v);
}
mashina ★★★★★
()

Парсер слабо написать?

anonymous
()
$ cat test.c
#include <stdio.h>
#include <stdlib.h>

int main(int argc, char *argv[])
{
    printf("%.20f\n", strtod("0.73079299926757812", NULL));
    return 0;
}
$ gcc test.c
$ ./a.out
0.73079299926757812500
ksv
()

>Даже если введено число с 10-ю символами после запятой.

Ага, и дюжина цифр до запятой. Угадал? :)

JackYF ★★★★
()
Ответ на: комментарий от mashina

ОК. Значит, виноват не strtod.

Отвечаю вам, а также тем, кто предлагает устанавливать у printf фиксированную точность:

printf("%.20f\n", var);
Не подходит, т.к. выдает такую чушь: 1.43234560000000010760 вместо введенного 1.4323456.

Значит, теперь такой вопрос: как сделать нормальное преобразование double в строковую переменную? Чтобы и все числа после запятой отображалиь, и всякий мусор не выскакивал (да и лишних нулей не было)?

Eddy_Em ☆☆☆☆☆
() автор топика
Ответ на: комментарий от mashina

>Немного капитана: printf() по умолчанию выводит как раз 6 знаков после запятой.

Да, ты прав.

JackYF ★★★★
()
Ответ на: комментарий от Eddy_Em

Совсем издеваешься над ЛОРом? Марш читать что такое числа с плавающей точкой. Тебе, похоже, нужно Decimal floating point, чего в стандартном си нет.

mashina ★★★★★
()

Все, всем спасибо. Извиняюсь за тупость. Проверку double-числа сделал в виде такой функции:

void mystrtod(char **val, double d_val){
	char *eptr = NULL, *ptr = *val;
	d_val = strtod(ptr, &eptr);
	if((eptr && *eptr) || errno == ERANGE){
		*val = g_strdup_printf("%g", d_val);
		g_err(_("Invalid double number!"));
	}
}
Т.е. если в конвертировании числа ошибок не было, содержимое строковой переменной не изменяется. Иначе вместо него записывается распознанная часть с точностью 6 знаков (хватит, если введенное число все равно содержало ошибки).

P.S. Если перед g_strdup_printf сделать g_free(*val), программа в случайные моменты времени падает с ошибкой нарушения памяти. Если g_free убрать, как в данном случае, все ОК. Но не будет ли при этом подтекать память?

Eddy_Em ☆☆☆☆☆
() автор топика
Ответ на: комментарий от namezys

Вроде взрослый мальчик

Да ладно вам. Совсем пристыдили человека. С кем не бывает.

pathfinder ★★★★
()
Ответ на: комментарий от Eddy_Em

>Не подходит, т.к. выдает такую чушь: 1.43234560000000010760 вместо введенного 1.4323456.

Там мантисса 15 десятичных знаков, а экспонента от -1022 до -1023. Поскольку физически мантисса хранится в двоичном формате, а десять не является степенью двойки, то после 15-го знака образуется всякий мусор.

Переходи на языки с бесконечной экспонентой, гы.

Absurd ★★★
()
Ответ на: комментарий от Eddy_Em

Все, с P.S. тоже разобрался: я в функцию, проверяющую введенные числа, передавал gchar*, а не gchar**.

Еще раз всем спасибо, проблема закрыта.

Eddy_Em ☆☆☆☆☆
() автор топика
Ответ на: комментарий от Absurd

Блин, с бесконечной мантиссой конечно же.

Absurd ★★★
()
Ответ на: комментарий от Eddy_Em

Да, функцию криво написал. Конечно же надо так:

void mystrtod(gchar **val, double *d_val){
	char *eptr = NULL, *ptr = *val;
	*d_val = strtod(ptr, &eptr);
	if((eptr && *eptr) || errno == ERANGE){
		g_free(*val);
		*val = g_strdup_printf("%g", *d_val);
		g_err(_("Invalid double number!"));
	}
}

Eddy_Em ☆☆☆☆☆
() автор топика
Ответ на: комментарий от Eddy_Em

Проверку double-числа сделал в виде такой функции:

Что-то меня пугает этот код.

d_val = strtod(ptr, &eptr);
if((eptr && *eptr) || errno == ERANGE){

Объясните глупому, errno всегда изменяется при вызове библиотечной функци или есть шанс схватить errno == ERANGE, полученный в результате выполнения некоторое другой библиотечной функции ранее.

pathfinder ★★★★
()
Ответ на: комментарий от pathfinder

Точно, об этом даже в мане strtod написано. Добавил до вызова функции errno = 0;

Eddy_Em ☆☆☆☆☆
() автор топика
Ответ на: комментарий от Eddy_Em

Только экспоненциальная форма дает тебе всегда правильное число значащих цифр независимо от того, каков порядок числа.

unanimous ★★★★★
()
Вы не можете добавлять комментарии в эту тему. Тема перемещена в архив.