| Версия для печати темы
Нажмите сюда для просмотра этой темы в оригинальном формате |
| Форум программистов > C/C++: Общие вопросы > Десятичная дробь - не понятки... |
| Автор: ressac 19.12.2006, 20:19 | ||
привет всем. ;)
Вот прога которая по идее должна считать сколько цифр после запятой, на теории всё работает , а вот на практике нет например я ввожу цифру "0.01" а реально получаю вот что ---> "0.00999999977648258210000000000000000000000000000000000000000000000000000000000000" или "0.1" а получаю "0.10000000149011612000000000000000000000000000000000000000000000000000000000000000" так вот вопрос в том, откуда берутся эти левый цифры? в них вся проблема , если бы их не было цикл повторялся ровно столько сколько есть цифр в ведёном номере тойсть если "0.1" то он и повторится один раз но так как появляются другие цифры то ясно что он и будет повторятся больше чем один раз короче SOMEBODY HELP ME PLEASE спасибо пока. ;) p.s. там ещё принтфы я напихал, это для того чтоб было наглядно видно что мы имеем после каждой операции. Я юзаю gcc компиль может в борлонде будет всё по другому хз. |
| Автор: nickless 19.12.2006, 20:37 | ||
Компьютер хранит числа в двоичной системе и с ограниченной точностью, поэтому числа, которые не возможно точно представить в двоичной системе, округляются. Hапример 1/10=1/(2*5), 5 на 2 не делится. Если тебе не обязательно надо float, считывай в char* и считай цифры там, или сначала округляй float, пиши его в char* и считай там. |
| Автор: sergejzr 19.12.2006, 20:50 |
| Возможных десятичных чисел - бесконечное количество, а вот бит для представления - количество очень даже ограниченное (32). Из этого следует, что невозможно любую десятичную дробь точно представить. Поэтому числа и "округляются" |
| Автор: ressac 19.12.2006, 20:59 |
| nickless, не совсем тебя понял насчёт char |
| Автор: nickless 19.12.2006, 21:39 | ||||
Я имел ввиду число просто как строку сохранить, а потом просто посчитать сколько букв между точкой/запятой и концом строки.
|
| Автор: Dov 19.12.2006, 21:53 | ||||
Отсюда
Ты указал точность: 80 знаков после запятой. |
| Автор: W4FhLF 19.12.2006, 21:53 |
| Всё дело в том, что в данном случае тип float есть короткий формат представления дробных чисел в памяти, точность вычисления 6 знаков после запятой, после чего идёт округление самим арифметическим сопроцессором, при расчёте дробной части всё, что после 6 знака просто не учитывается, поэтому выводить 80 знаков после запятой не имеет никакого смысла. Максимальная точность у расширенного формата, там точность достигает 19 знаков после запятой. |
| Автор: nickless 19.12.2006, 22:01 | ||
Даже если поставить 4 знака, считать всё равно будет неправильно, потому что число каждый раз округляется. |
| Автор: nickless 19.12.2006, 22:45 | ||
Tаблица? Инициализируешь num нулём, смотришь длину строки, в цикле с конца пропускаешь нули, потом увеличиваешь num, пока не найдешь точку, а если не найдешь, значит num = 0... |
| Автор: ressac 19.12.2006, 22:47 |
| nickless, я вообщем не понял, о чём ты говоришь, я наверно просто ещё не знаком с этим, если тебе не трудно преведи малый пример. спасибо.. |
| Автор: nickless 19.12.2006, 23:17 | ||
|
| Автор: ressac 19.12.2006, 23:36 |
| nickless, в принципе понял, я это ещё просто не изучал интересно. вот только одно не пойму зачем ты тут "i=strlen(str)-1" ставишь минус один? спасибо |
| Автор: nickless 19.12.2006, 23:45 | ||
Потому что массивы в C(++) с нуля начинаются, первая буква находится в str[0], последняя в str[length-1] |
| Автор: Dov 20.12.2006, 00:20 | ||
|
| Автор: W4FhLF 20.12.2006, 08:56 | ||
Тут ещё зависит от разрядности целой части, double является длинным форматом представления float point чисел, где под мантиссу или дробную часть числа отводится 53 байта, что при нулевом значении целой части может дать точность до 16 знаков после запятой. |
| Автор: ressac 23.12.2006, 00:34 |
| я вернусь к старому , к тому с чего и начал, проблему которую я тут запостил можно разрешить по старинке просто с for'ом? без char'ов и подобных вещей. просто один FOR. |
| Автор: Anikmar 23.12.2006, 00:59 |
| На мой взгляд нельзя. Когда ты вводишь цифры с клавиатуры - ты вводишь все равно char, что бы там не говорили. ты вводишь 0.01 - это символы. потом среда (программа) преобразует эти цифры в float. Бинарная точность float далеко не всегда совпадает с десятичной. Если ты ввел 0.01 - программа пытается преобразовать это во float с максимальной точностью. получается (это только пример) некое число в формате float. Оно может вглыдеть как 0.009999999999999999999999999999999999. Если воспользоваться твоим алгоритомом - получишь результат, который ты уже видел. Следовательно - чисто математическими методами здесь никак не обойтись - все равно будет погрешность. Резюме: Я бы задал некоторую точность: допустим программа работает с числами, которые не превышают 10 знаков после запятой. Тогда можно введенное число округлить до этой точности, а потом воспользоваться твоим алгоритмом. Я бы использовал метод: Допустим ввели 120344.04563 Сначала - привел бы число к значению меньше 1 (последовательным делением на 10) Получил бы результат 0.04563 Потом умножил бы на 10000000000 (до кличества знаков) - это уже можно делать в типе long int В результате получил бы число 456300000 Дальше можно по алгоритму - с целыми числами он сработает (при некой модификации) Моя мысля должна работать до предела знаков после запятой, равной длине (long) int... Если ошибся - не бейте. |
| Автор: ressac 23.12.2006, 01:26 |
| ты не ошибся вроде бы всё хорошо,только с нулями в конце что будем делать? (я не совсем понял этот момент). |
| Автор: Anikmar 23.12.2006, 10:16 | ||
| Незначащие конечные нули - выбрасываем. Наверное надо сделать цикл вроде
Что-то в этом роде Видимо не проснулся - немного подправил |
| Автор: Dov 23.12.2006, 11:36 |
| ... ... ... По-моему, чего-то не того. 5 != 4. |
| Автор: ressac 23.12.2006, 11:55 | ||
хорошо только ведь этот блок будет отбирать и нужные нам нули , понимаешь о чём я говорю?
тойсть было "0,02" умножили на 100....... получили двойку в конце с кучей нолей и затем их убрали и один нужный нолик нам мы потеряли, в принципе можно совместить твой и мой алгоритм, мой будет считать сколько нолей до первой цифры (это у него получается вроде-бы если я не ошибаюсь) а твой затем будет переносить их на левую часть дроби и считать цифры, вроде должно пройти, но минус есть серовно, максимальное чилсо будет состоять из 10 цифр, ну это лучше чем ничего всё таки 2Dov я не понял о чём ты. или ты о том-же о чём и я? |
| Автор: Anikmar 23.12.2006, 12:30 |
| На самом деле - если работать чисто с числами там все равно будет куча цифр, которые пользователь не вводил. Число 56.0475 будет представлено как 56.047499999999999999999999999 Так что все-таки проще разобрать введенную строку и посчитать количество знаков после запятой. Конечные нули можно и обрезать. Это будет наипростейший и самый правильный выход. А так, в большинстве случаев будет выдаваться результат, совпадающий с заданной точностью. |
| Автор: Dov 23.12.2006, 12:35 |
ressac, я о том, что нужный ноль был утерян не после того, как получили двойку в конце с кучей нолей и затем их убрали, а после того, как умножили на 100. |
| Автор: Rockie 23.12.2006, 14:27 | ||
Вводишь пиксели а они потом там, по проводочкам, преобразуются |
| Автор: Anikmar 23.12.2006, 15:04 |
Ну если быть совсем точным, то при нажатии клавиши формируется прерывание 09, обработчик прерывания считывает SCAN-код клавиши, и помещает его в буффер Драйвер клавиатуры считывает из буфера этот скан-код, преобразовывает его в код клавиши и отправляет в буфер нажатых клавиш. Винда берет этот код, посылает активному окну сообщение о нажатии клавиши. Соответственно обработчик данного сообщения берет код нажатой клавиши и помещает его в сандартный поток ввода. Несколько упрощенно, но где-то так. Так вот: в стандартный поток ввода помещается char! |
| Автор: Rockie 23.12.2006, 16:37 | ||||
Anikmar, то есть я сейчас char считал?
А если я Ctrl+Alt+Del жмакаю я какой char ввожу?.. Клавиатура здесь вообще не при чем, это не единственный способ ввести число. |
| Автор: ressac 23.12.2006, 20:49 | ||
| силь больше нет думать погрешности при вычислениях есть и будут... у кого-то есть идеи получше ?
|
| Автор: Anikmar 23.12.2006, 22:04 | ||
Ну вообще-то я в шутку писал Но на самом деле, если серьезно, когда ты вводишь с клавиатуры символы 345.04567, которые преобрразуются в double, а потом в отладчике посмотришь чему этот double равен - ты увидишь немного отличающееся значение. Это и есть погрешность преобразования десятичного числа в двоичное (коим double собственно и является). Если в задаче стоит посчитать количество знаков после запятой в десятичном числе - нужно воспользоваться строковым выражением - т.е. преобразовать число в строку с заданным параметром округления. Если число вводится с клавиатуры - надо сразу его обрабатывать как строку. Если число формируется программно - точного результата достичь не получится - с этим ничего нельзя сделать, особенности архитектуры. Тут можно использовать не двоичную систему - а прямую трансляцию десятичной в двоичную (точно не помню, по-моему такое называется BCD, но не уверен). Но в рамках поставленной задачи не уверен, что это необходимо. |
| Автор: ressac 24.12.2006, 04:09 |
| а можно-ли одновремено сохранить число в строку(чар) и в перменую? в том момент когда мы вводим его? |
| Автор: Anikmar 24.12.2006, 10:10 | ||||
Конечно. Вводим в строку, а потом строку преобразовываем в число.
|
| Автор: bsa 24.12.2006, 13:41 | ||
у него программа на C. Поэтому в его случае лучше использовать:
Если же надо считать количество значащих разрядов после запятой у любого числа (а не только введенного с клавиатуры), то тут надо делать цикл от 0 до количества разрядов, точность которых гарантирована типом (для флоат кто-то тут написал 6 десятичных разрядов, для double - 19). Все что за пределами точности типа необходимо игнорировать. |