8 / 4 / 0
Регистрация: 11.04.2012
Сообщений: 54
1

Компилятор сломался или ошибка?

26.07.2012, 17:08. Показов 3976. Ответов 31
Метки нет (Все метки)

Author24 — интернет-сервис помощи студентам
Требуется написать программу, которая делает перевод вещественного числа в строку.
Возникает ошибка во время получения дробной части числа.
Например:

C++
1
2
3
double f = 12.23;
int whole = (int) f; //=12
double real = f - whole;  // должно быть 0.23 но может получиться = 0.2300000012
Почему так и как это можно исправить?
C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
//обращение строки
void RevStr(char *str){
    char *start,*end;
    char t;
    
    start = str;
    end = &str[strlen(str) -1];
 
    while(end > start){
        t = *end;
        *end = *start;
        *start = t;
        start++; end--;
    }
}
 
//перевод вещественного числа в строку
char * ConvertToString(double f){
    char result[80];
    int whole;
    double real;
    
    whole = (int) f;    //переменная для целой части
    real = f - whole;   //переменная для вещественной части
    
    int i = 0;
    
    //целую часть заносим в строку в обратном порядке
    do{
        result[i] = (whole % 10) + '0';
        i++;
    }while(whole /= 10);
    
    result[i] = 0;
    
    //развернём строку
    RevStr(result);
 
    result[i++] = '.';
    
 
    if(real == 0){
        result[i] = result[i+1] = '0';
        result[i+2] = 0;
        return result;
    }
    
    int serv;
 
 
    //заносим в строку вещественную часть
    while(real){
        serv = (int)(real * 10);
        result[i] = serv + '0';
        real = real * 10 - serv;
        i++;
    }
 
    result[i] = 0;
    return result;
}
0
Лучшие ответы (1)
Programming
Эксперт
94731 / 64177 / 26122
Регистрация: 12.04.2006
Сообщений: 116,782
26.07.2012, 17:08
Ответы с готовыми решениями:

Ошибка в коде или компилятор не понимает меня?
Добрый день. Изучаю, с недавнего времени, с++ по книге Джесса Либерти "С++ за 21 день". Использую...

Компилятор не дает написать main без int. Ошибка в книге, или в С так можно?
В книге И.Ш. Хабибуллина "Программирование на языке высокого уровня C/C++" во всех примерах пишут...

Сломался пробел или нет?
Случайно пролил чай на клавиатуру высушил все кнопки работают а когда нажимаю пробел открывается...

роутер сломался или я ошибаюсь
Роутер(DLink DIR 615) работает нормально полгода, иногда случались казусы резкого прекращения...

31
Модератор
Эксперт функциональных языков программированияЭксперт Python
36354 / 20233 / 4211
Регистрация: 12.02.2012
Сообщений: 33,508
Записей в блоге: 13
26.07.2012, 17:35 2
Вещественные числа хранятся и обрабатываются с погрешностью. И, поскольку, хранятся они в двоичном виде, вполне может оказаться, что конечная десятичная дробь будет двоичной периодической.
1
8 / 4 / 0
Регистрация: 11.04.2012
Сообщений: 54
26.07.2012, 17:37  [ТС] 3
Каким способом можно избежать этих ошибок?
0
Модератор
Эксперт функциональных языков программированияЭксперт Python
36354 / 20233 / 4211
Регистрация: 12.02.2012
Сообщений: 33,508
Записей в блоге: 13
26.07.2012, 17:45 4
Лучший ответ Сообщение было отмечено как решение

Решение

Некоторых ошибок подобного класса избежать невозможно. Но кое-какие рекомендации дать можно:

1) не используйте float, используйте double (погрешность будет меньше, но не исчезнет);
2) при вычислениях выражения преобразуйте так, чтобы избежать вычитания близких чисел (особенно плохо, если эта разность потом многократно умножается на что-либо; в этом случае ошибка может накопиться и стать огромной).
4
8 / 4 / 0
Регистрация: 11.04.2012
Сообщений: 54
26.07.2012, 17:57  [ТС] 5
Вот смотрите, если int занимает 4 байта, то в моём коде лучше взять float или double?
0
Модератор
Эксперт функциональных языков программированияЭксперт Python
36354 / 20233 / 4211
Регистрация: 12.02.2012
Сообщений: 33,508
Записей в блоге: 13
26.07.2012, 18:04 6
Э... А при чем здесь int? Целая часть числа float и, тем более, double, может быть такой, что никакого int не хватит. Пример: число Авогадро =~ 6.02*1023= 602000000000000000000000
Поэтому переводить числа с плавающей точкой нужно по-другому (без int-посредников).
0
~ Эврика! ~
1256 / 1005 / 74
Регистрация: 24.07.2012
Сообщений: 2,002
26.07.2012, 20:02 7
Цитата Сообщение от gmb124
Требуется написать программу, которая делает перевод вещественного числа в строку.

Почему так и как это можно исправить?
За подробностями представления вещественных чисел — google://IEEE 754. Там всё не так просто.
Почему: потому что точно с помощью float/double могут быть представлены только некоторые десятичные дроби.
Как исправить: никак. Можно только не использовать числа с плавающей точкой для точных вычислений.
За дальнейшими подробностями о том, как бороться с ошибками округления — Д. Кнут, Искусство программирования, том 2, глава 4, раздел 2.
Цитата Сообщение от gmb124
Каким способом можно избежать этих ошибок?
Не городить велосипеды, коли не умеем их проектировать, а написать нечто подобное:
C++
1
2
3
4
5
6
#include <stdio.h>
char* double2str(char *str, double num)
{
  sprintf(str, "%f", num);
  return str;
}
0
Эксперт С++
5043 / 2622 / 241
Регистрация: 07.10.2009
Сообщений: 4,310
Записей в блоге: 1
26.07.2012, 20:16 8
Цитата Сообщение от ~OhMyGodSoLong~ Посмотреть сообщение
Не городить велосипеды, коли не умеем их проектировать, а написать нечто подобное:
Ручки бы вам поотрывать за такие велосипеды
Используйте stringstream.
1
8 / 4 / 0
Регистрация: 11.04.2012
Сообщений: 54
26.07.2012, 21:10  [ТС] 9
Я согласен, можно конечно использовать готовые средства. Но цель данной темы разобраться, как написать функцию, которая переводит числа вещественное в строку. Есть идеи?
0
Evg
Эксперт CАвтор FAQ
21276 / 8298 / 637
Регистрация: 30.03.2009
Сообщений: 22,659
Записей в блоге: 30
26.07.2012, 21:36 10
Если вдруг интересено
https://www.cyberforum.ru/blogs/18334/blog88.html
1
Модератор
Эксперт функциональных языков программированияЭксперт Python
36354 / 20233 / 4211
Регистрация: 12.02.2012
Сообщений: 33,508
Записей в блоге: 13
26.07.2012, 22:37 11
Те, кто не хочет "изобретать велосипеды", никогда не изобретут ничего путного. Если интересно, как преобразовать число с плавающей точкой в строку, то вот:

C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
#include "math.h"
#include "iostream.h"
 
char * Dbl2Str(double x)
{
    char * buf = new char[24];
    int  p10,i,n,q=100;
 
    for (i=0; i<24; i++) buf[i]=0;
 
    buf[0]='0';
    buf[1]='.';
 
    p10=(int)log10(x); // äåñÿòè÷íûé ïîðÿäîê
 
    // äåñÿòè÷íàÿ íîðìàëèçàöèÿ ìàíòèññû
 
    if (p10 > 1)
    {   p10++;
        for (i=1; i<=p10; i++) x=x/10.0;
    }
    
    if (p10 < -1)
        for (i=1; i<=abs(p10); i++) x=x*10.0;
 
    // Ïîëó÷àåì ìàíòèññó
 
    for (i=1; i<=15; i++)
    {
        x=x*10.0;
        n=(int)x;
        x=x-n;
        buf[i+1]='0'+n;
 
    }
    
    buf[17]='D';
 
    // çíàê ïîðÿäêà
 
    if (p10 < 0)
        buf[18]='-';
    else
        buf[18]='+';
 
    p10=abs(p10);
 
    // ïîðÿäîê
 
    for (i=1; i<=3; i++)
    {
        n=p10/q;
        buf[18+i]='0'+n;
        p10=p10%q;
        q=q/10;
    }
 
    return buf;
 
}
 
int main(int argc, char* argv[])
{
 
    char *S1=Dbl2Str(0.00012345789);
    char *S2=Dbl2Str(663663.88958);
 
    cout << S1 << endl;
    cout << S2 << endl;
 
    delete [] S1;
    delete [] S2;
 
    return 0;
}
Функция переводит в строковый вид только положительные числа (настучал на скорую руку). Перевод отрицательных оставляю интересующимся в качестве упражнения.
1
kravam
26.07.2012, 23:00
  #12

Не по теме:

Сдаётся мне, вещественные числа представлены в памяти компьютера однозначно. Неоднозначен их вывод. Почему- не знаю.

0
Evg
Эксперт CАвтор FAQ
21276 / 8298 / 637
Регистрация: 30.03.2009
Сообщений: 22,659
Записей в блоге: 30
26.07.2012, 23:28 13
Цитата Сообщение от kravam Посмотреть сообщение
Почему- не знаю
Как по твоему должна выглядеть печать числа 1/3 в десятичном виде?
0
быдлокодер
1724 / 911 / 106
Регистрация: 04.06.2008
Сообщений: 5,678
27.07.2012, 00:05 14
0,(3)
0
Evg
Эксперт CАвтор FAQ
21276 / 8298 / 637
Регистрация: 30.03.2009
Сообщений: 22,659
Записей в блоге: 30
27.07.2012, 08:18 15
Цитата Сообщение от kravam Посмотреть сообщение
0,(3)
Всё-таки у тебя отсутствует воображение. Тогда переформулирую вопрос. Как по твоему должна выглядеть печать числа 1/7 в десятичном виде?
0
быдлокодер
1724 / 911 / 106
Регистрация: 04.06.2008
Сообщений: 5,678
27.07.2012, 10:06 16
Цитата Сообщение от Evg Посмотреть сообщение
Всё-таки у тебя отсутствует воображение


Цитата Сообщение от Evg Посмотреть сообщение
Как по твоему должна выглядеть печать числа 1/7 в десятичном виде?
0.142857
0
Эксперт С++
5043 / 2622 / 241
Регистрация: 07.10.2009
Сообщений: 4,310
Записей в блоге: 1
27.07.2012, 10:44 17
Цитата Сообщение от kravam Посмотреть сообщение
0.142857
Всего 6 знаков?
0
317 / 268 / 61
Регистрация: 12.10.2011
Сообщений: 434
27.07.2012, 10:59 18
1/7=0,(001)2
0
быдлокодер
1724 / 911 / 106
Регистрация: 04.06.2008
Сообщений: 5,678
27.07.2012, 11:33 19
Цитата Сообщение от fasked Посмотреть сообщение
Всего 6 знаков?
ну у меня больше не выводит если
0
Evg
Эксперт CАвтор FAQ
21276 / 8298 / 637
Регистрация: 30.03.2009
Сообщений: 22,659
Записей в блоге: 30
27.07.2012, 15:43 20
kravam, опять фантазии нет. Тогда двигаемся дальше

C
#include <stdio.h>
 
int main (void)
{
  double d = 1.0/7.0;
 
  printf ("%.5f\n", d);
  printf ("%.6f\n", d);
  printf ("%.7f\n", d);
 
  return 0;
}
напечатает

Bash
0.14286
0.142857
0.1428571
Попробуй вычислить на листочке (столбиком) значение 1/7 и затем попробуй ответить на свой собственный вопрос:

Цитата Сообщение от kravam Посмотреть сообщение
Неоднозначен их вывод. Почему- не знаю.
0
27.07.2012, 15:43
IT_Exp
Эксперт
87844 / 49110 / 22898
Регистрация: 17.06.2006
Сообщений: 92,604
27.07.2012, 15:43
Помогаю со студенческими работами здесь

Сломался телефон матрица или экран
Сломался телефон думаю матрица или экран

Сломался блок питания или что то еще?
Предисловие - комп не включается. Загорается/жужжит ( как обычно) все кроме вентилятора на блоке...

Сломался Fast Report. Или Access violation in module 'fs19.bpl'
Имеется: Fast Report 4.0 RAD Studio XE5 Builder На форме: frxReport, frxDBDataset, ADOQuery...

"Ошибка ввода\вывода 102" или "пьяный компилятор"
program matrix4; const n=2; k=10; var A:array of integer; i,j:integer; begin ...


Искать еще темы с ответами

Или воспользуйтесь поиском по форуму:
20
Ответ Создать тему
Опции темы

КиберФорум - форум программистов, компьютерный форум, программирование
Powered by vBulletin
Copyright ©2000 - 2024, CyberForum.ru