Форум программистов, компьютерный форум CyberForum.ru

LONG VS DOUBLE / INT VS FLOAT - C++

Восстановить пароль Регистрация
 
magicofwater
0 / 0 / 0
Регистрация: 11.06.2014
Сообщений: 5
11.06.2014, 12:31     LONG VS DOUBLE / INT VS FLOAT #1
Всем доброго времени суток!
Объясните пожалуйста почему при следующем коде
C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
#include <iostream>
using namespace std;
int main()
{
            long e;
            long a = 196;
            double b = a/60.0;
            cout << "a = " << a << endl;
            cout << "b = " << b << endl;
            long c = static_cast<int>(b); // отбрасывание дробной части
            cout << "c = " << c << endl;
            double d = (b - c) * 60;
            cout << d << endl;
            e = d;
            cout << e << endl;
        return 0;
}
Результат d = 16 (так правильно), а результат e = 15???
Спасибо!
После регистрации реклама в сообщениях будет скрыта и будут доступны все возможности форума.
tehnar5
31 / 31 / 12
Регистрация: 03.05.2011
Сообщений: 84
11.06.2014, 13:01     LONG VS DOUBLE / INT VS FLOAT #2
Это особенности поведения даблов. Суть в том, что если d = 15.99999999999 вследствие потери точности, то при выведении его как дабла, он округлится нормально, а при выведении как инта целая часть отбросится и будет 15. Приводить к целому типу лучше, прибавляя какое-нибудь небольшое число, например, 0.000000001, чтобы избежать таких потерь в точности

Добавлено через 2 минуты
Вместо e = d надо сделать e = d + 0.000001. Да и
static_cast<int>(b) лучше заменить на static_cast<int>(b + 0.0000001)
magicofwater
0 / 0 / 0
Регистрация: 11.06.2014
Сообщений: 5
11.06.2014, 13:04  [ТС]     LONG VS DOUBLE / INT VS FLOAT #3
Я думал об этом. Но если выполнить действия
a = 196
b = 196/60=3,266667
c = 3
d = (3,266667 - 3) * 60 = 16.00002
Что больше 16. Соответсвенно, если следовать Вашей версии, то ответ должен быть 16.
tehnar5
31 / 31 / 12
Регистрация: 03.05.2011
Сообщений: 84
11.06.2014, 13:17     LONG VS DOUBLE / INT VS FLOAT #4
Вы не совсем правильно оцениваете точность операций. Дабл хранит, если не ошибаюсь, около 20 знаков после запятой, округляя только последний. При этом, в нескольких последних знаках могут быть ошибки. В частности,
C++
1
2
cout.precision(20);
cout << d << endl;
выводит
15.999999999999996447
Croessmah
Модератор
Эксперт С++
 Аватар для Croessmah
11807 / 6786 / 767
Регистрация: 27.09.2012
Сообщений: 16,839
Записей в блоге: 2
Завершенные тесты: 1
11.06.2014, 13:20     LONG VS DOUBLE / INT VS FLOAT #5
Цитата Сообщение от tehnar5 Посмотреть сообщение
около 20 знаков после запятой
Википедия: Число двойной точности
tehnar5
31 / 31 / 12
Регистрация: 03.05.2011
Сообщений: 84
11.06.2014, 13:21     LONG VS DOUBLE / INT VS FLOAT #6
Цитата Сообщение от Croessmah Посмотреть сообщение
Википедия: Число двойной точности
Согласен, был не совсем прав, но суть это не меняет, с округлением надо быть осторожнее.
uglyPinokkio
325 / 228 / 41
Регистрация: 30.05.2014
Сообщений: 682
11.06.2014, 13:24     LONG VS DOUBLE / INT VS FLOAT #7
Цитата Сообщение от tehnar5 Посмотреть сообщение
Приводить к целому типу лучше, прибавляя какое-нибудь небольшое число, например, 0.000000001,
0.5
tehnar5
31 / 31 / 12
Регистрация: 03.05.2011
Сообщений: 84
11.06.2014, 13:29     LONG VS DOUBLE / INT VS FLOAT #8
Цитата Сообщение от uglyPinokkio Посмотреть сообщение
Сообщение от tehnar5
Приводить к целому типу лучше, прибавляя какое-нибудь небольшое число, например, 0.000000001,
0.5
Нет же, тут цель - обрубить дробную часть, а не округлить число по правилам округления

Добавлено через 53 секунды
Да и Ваш способ и для округления не годится для случая отрицательных чисел
magicofwater
0 / 0 / 0
Регистрация: 11.06.2014
Сообщений: 5
11.06.2014, 13:32  [ТС]     LONG VS DOUBLE / INT VS FLOAT #9
ЭТО РАБОТАЕТ
Вместо e = d надо сделать e = d + 0.000001.
ЭТО НЕ РАБОТАЕТ
Да и static_cast<int>(b) лучше заменить на static_cast<int>(b + 0.0000001)
Почему 0.5, а не 0.6, 0.00001, 0.3?
А более надежные способы есть? Или всегда прибавлять 0.000001 и не задумываться?
Renji
1533 / 981 / 239
Регистрация: 05.06.2014
Сообщений: 2,950
11.06.2014, 13:38     LONG VS DOUBLE / INT VS FLOAT #10
А более надежные способы есть? Или всегда прибавлять 0.000001 и не задумываться?
floor - округление вниз, ceil - округление вверх, round - к ближайшему целому. Иначе - шаманить с флагами процессора, через ассемблерные вставки.
tehnar5
31 / 31 / 12
Регистрация: 03.05.2011
Сообщений: 84
11.06.2014, 13:42     LONG VS DOUBLE / INT VS FLOAT #11
Цитата Сообщение от magicofwater Посмотреть сообщение
ЭТО НЕ РАБОТАЕТ
Да и static_cast<int>(b) лучше заменить на static_cast<int>(b + 0.0000001)
В данном конкретном случае не работает, так как проблема была только с переменной d. Никаких более надежных способов я не знаю, кроме способа создать свою собственную функцию
C++
1
2
3
4
5
int toInt(double a)
{
    return int(a + 0.0000001);
    return static_cast<int>(a + 0.0000001);
}
Выбирайте любой из двух return-ов, они оба делают, по сути, одно и то же

Добавлено через 2 минуты
Цитата Сообщение от Renji Посмотреть сообщение
floor - округление вниз
Только он тоже возвращает float/double, не знаю, могут ли быть проблемы или нет, но мало ли...
uglyPinokkio
325 / 228 / 41
Регистрация: 30.05.2014
Сообщений: 682
11.06.2014, 13:45     LONG VS DOUBLE / INT VS FLOAT #12
Цитата Сообщение от magicofwater Посмотреть сообщение
Почему 0.5
По правилам округления - все что больше 0.5 округлится вверх, все что меньше вниз.
Если надо строго вверх или вниз - fllor и ceil как уже подсказали.

Цитата Сообщение от tehnar5 Посмотреть сообщение
Да и Ваш способ и для округления не годится для случая отрицательных чисел
округление по модулю пока не отменили.
tehnar5
31 / 31 / 12
Регистрация: 03.05.2011
Сообщений: 84
11.06.2014, 13:49     LONG VS DOUBLE / INT VS FLOAT #13
Цитата Сообщение от uglyPinokkio Посмотреть сообщение
округление по модулю пока не отменили.
В смысле? Как ни крути, -0.7 должно округляться до -1, если по правилам, а Вы хотите округлить до нуля, так как int(-0.2) == 0
Renji
1533 / 981 / 239
Регистрация: 05.06.2014
Сообщений: 2,950
11.06.2014, 13:52     LONG VS DOUBLE / INT VS FLOAT #14
Только он тоже возвращает float/double, не знаю, могут ли быть проблемы или нет, но мало ли...
Проблемы у вас были потому что 196/60.0 дало бесконечную дробь, а число разрядов в double конечно. В принципе можно обойти если использовать числа в формате числитель/знаменатель, но не уверен что они есть в стандартной библиотеке. floor же дает целое число, с ним проблем быть не должно. При условии что оно в int влезает.
uglyPinokkio
325 / 228 / 41
Регистрация: 30.05.2014
Сообщений: 682
11.06.2014, 13:54     LONG VS DOUBLE / INT VS FLOAT #15
Цитата Сообщение от tehnar5 Посмотреть сообщение
В смысле?
-(0.7+0.5)
tehnar5
31 / 31 / 12
Регистрация: 03.05.2011
Сообщений: 84
11.06.2014, 13:59     LONG VS DOUBLE / INT VS FLOAT #16
Цитата Сообщение от Renji Посмотреть сообщение
floor же дает целое число, с ним проблем быть не должно
Да, соглашусь. Вообще, видимо, единственные безопасные в плане точности операции с double - с целыми числами и целыми числами, поделенными на степень двойки, не очень большую
magicofwater
0 / 0 / 0
Регистрация: 11.06.2014
Сообщений: 5
11.06.2014, 16:16  [ТС]     LONG VS DOUBLE / INT VS FLOAT #17
Да, соглашусь. Вообще, видимо, единственные безопасные в плане точности операции с double - с целыми числами и целыми числами, поделенными на степень двойки, не очень большую
Ваше высказывание вообще не понял

Добавлено через 24 минуты
После мозгового штурма (спасибо всем) я написал так (оставлю здесь для истории)
C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
#include <iostream>
#include <math.h>       /* floor, ceil, round (C99 и выше)*/
 
using namespace std;
int main()
{
            long e;
            long a = 196;
            double b = a/60.0;
            cout << "a = " << a << endl;
            cout << "b = " << b << endl;
            long c = static_cast<int>(b); // отбрасывание дробной части
            cout << "c = " << c << endl;
            double d = (b - c) * 60;
            cout << d << endl;
            //e = d+0.0000000001;
            e = roundl (d);
            cout << e << endl;
        return 0;
}
roundl
long double roundl (long double x);
описана тут
uglyPinokkio
325 / 228 / 41
Регистрация: 30.05.2014
Сообщений: 682
11.06.2014, 17:17     LONG VS DOUBLE / INT VS FLOAT #18
Цитата Сообщение от magicofwater Посмотреть сообщение
После мозгового штурма (спасибо всем) я написал так (оставлю здесь для истории)
ну т.е нужно было корректное округление до целого, которое с лохматых годов делается прибавлением 0.5 (с учетом знака, для особо пунктуальных )
magicofwater
0 / 0 / 0
Регистрация: 11.06.2014
Сообщений: 5
11.06.2014, 22:47  [ТС]     LONG VS DOUBLE / INT VS FLOAT #19
Цитата Сообщение от uglyPinokkio Посмотреть сообщение
ну т.е нужно было корректное округление до целого, которое с лохматых годов делается прибавлением 0.5 (с учетом знака, для особо пунктуальных )
17 строка
e = d + 0.5
Так?
а если учитывать знак то все равно придется использовать функцию (модуль)? Я правильно понял?
А если придется использовать функцию, то почему бы не использовать округление до ближайшего целого? Или так памяти больше тратится или время работы увеличивается? Глупости не наговорил?
MoreAnswers
Эксперт
37091 / 29110 / 5898
Регистрация: 17.06.2006
Сообщений: 43,301
12.06.2014, 05:14     LONG VS DOUBLE / INT VS FLOAT
Еще ссылки по теме:

float double int C++
C++ Как мне программу с int переделать в Float i double?
C++ Shot int b long double

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

Или воспользуйтесь поиском по форуму:
uglyPinokkio
325 / 228 / 41
Регистрация: 30.05.2014
Сообщений: 682
12.06.2014, 05:14     LONG VS DOUBLE / INT VS FLOAT #20
Цитата Сообщение от magicofwater Посмотреть сообщение
А если придется использовать функцию, то почему бы не использовать округление до ближайшего целого? Или так памяти больше тратится или время работы увеличивается? Глупости не наговорил?
Да нормальны все решения, которые дают правильный результат. Выбор - личное дело разработчика.
Yandex
Объявления
12.06.2014, 05:14     LONG VS DOUBLE / INT VS FLOAT
Ответ Создать тему
Опции темы

Текущее время: 17:37. Часовой пояс GMT +3.
КиберФорум - форум программистов, компьютерный форум, программирование
Powered by vBulletin® Version 3.8.9
Copyright ©2000 - 2016, vBulletin Solutions, Inc.
Рейтинг@Mail.ru