Форум программистов, компьютерный форум, киберфорум
Наши страницы
С++ для начинающих
Войти
Регистрация
Восстановить пароль
 
Рейтинг 4.60/5: Рейтинг темы: голосов - 5, средняя оценка - 4.60
magicofwater
0 / 0 / 0
Регистрация: 11.06.2014
Сообщений: 5
1

LONG VS DOUBLE / INT VS FLOAT

11.06.2014, 12:31. Просмотров 933. Ответов 19
Метки нет (Все метки)

Всем доброго времени суток!
Объясните пожалуйста почему при следующем коде
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???
Спасибо!
0
Similar
Эксперт
41792 / 34177 / 6122
Регистрация: 12.04.2006
Сообщений: 57,940
11.06.2014, 12:31
Ответы с готовыми решениями:

Размер для данных (int, char, long, double, short, unsigned, float)
Напишите программу, которая будет определять размер для данных (int, char,...

Создать динамический массив, любого простого типа (например: int, long, float, double)
1. Создать проект, который содержит консольную программу Win32. 2. Создать...

Напишите программу, которая будет определять размер для данных (int, char, long, double, short, unsigned, float) и выводить информацию
1. Какие типы данных лучше всего использовать для хранения следующих значений:...

Long float и double
В чем отличие long float от double?

Преобразовать 2 числа int в 1 число float(double) | double int1.int2
Всем привет. Изучая азы C++, столкнулся с такой проблемой. Есть два значения...

19
tehnar5
31 / 31 / 19
Регистрация: 03.05.2011
Сообщений: 84
11.06.2014, 13:01 2
Это особенности поведения даблов. Суть в том, что если d = 15.99999999999 вследствие потери точности, то при выведении его как дабла, он округлится нормально, а при выведении как инта целая часть отбросится и будет 15. Приводить к целому типу лучше, прибавляя какое-нибудь небольшое число, например, 0.000000001, чтобы избежать таких потерь в точности

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

Добавлено через 53 секунды
Да и Ваш способ и для округления не годится для случая отрицательных чисел
0
magicofwater
0 / 0 / 0
Регистрация: 11.06.2014
Сообщений: 5
11.06.2014, 13:32  [ТС] 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 и не задумываться?
0
Renji
2124 / 1562 / 476
Регистрация: 05.06.2014
Сообщений: 4,541
11.06.2014, 13:38 10
А более надежные способы есть? Или всегда прибавлять 0.000001 и не задумываться?
floor - округление вниз, ceil - округление вверх, round - к ближайшему целому. Иначе - шаманить с флагами процессора, через ассемблерные вставки.
0
tehnar5
31 / 31 / 19
Регистрация: 03.05.2011
Сообщений: 84
11.06.2014, 13:42 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, не знаю, могут ли быть проблемы или нет, но мало ли...
0
uglyPinokkio
326 / 229 / 55
Регистрация: 30.05.2014
Сообщений: 682
11.06.2014, 13:45 12
Цитата Сообщение от magicofwater Посмотреть сообщение
Почему 0.5
По правилам округления - все что больше 0.5 округлится вверх, все что меньше вниз.
Если надо строго вверх или вниз - fllor и ceil как уже подсказали.

Цитата Сообщение от tehnar5 Посмотреть сообщение
Да и Ваш способ и для округления не годится для случая отрицательных чисел
округление по модулю пока не отменили.
0
tehnar5
31 / 31 / 19
Регистрация: 03.05.2011
Сообщений: 84
11.06.2014, 13:49 13
Цитата Сообщение от uglyPinokkio Посмотреть сообщение
округление по модулю пока не отменили.
В смысле? Как ни крути, -0.7 должно округляться до -1, если по правилам, а Вы хотите округлить до нуля, так как int(-0.2) == 0
0
Renji
2124 / 1562 / 476
Регистрация: 05.06.2014
Сообщений: 4,541
11.06.2014, 13:52 14
Только он тоже возвращает float/double, не знаю, могут ли быть проблемы или нет, но мало ли...
Проблемы у вас были потому что 196/60.0 дало бесконечную дробь, а число разрядов в double конечно. В принципе можно обойти если использовать числа в формате числитель/знаменатель, но не уверен что они есть в стандартной библиотеке. floor же дает целое число, с ним проблем быть не должно. При условии что оно в int влезает.
0
uglyPinokkio
326 / 229 / 55
Регистрация: 30.05.2014
Сообщений: 682
11.06.2014, 13:54 15
Цитата Сообщение от tehnar5 Посмотреть сообщение
В смысле?
-(0.7+0.5)
0
tehnar5
31 / 31 / 19
Регистрация: 03.05.2011
Сообщений: 84
11.06.2014, 13:59 16
Цитата Сообщение от Renji Посмотреть сообщение
floor же дает целое число, с ним проблем быть не должно
Да, соглашусь. Вообще, видимо, единственные безопасные в плане точности операции с double - с целыми числами и целыми числами, поделенными на степень двойки, не очень большую
0
magicofwater
0 / 0 / 0
Регистрация: 11.06.2014
Сообщений: 5
11.06.2014, 16:16  [ТС] 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);
описана тут
0
uglyPinokkio
326 / 229 / 55
Регистрация: 30.05.2014
Сообщений: 682
11.06.2014, 17:17 18
Цитата Сообщение от magicofwater Посмотреть сообщение
После мозгового штурма (спасибо всем) я написал так (оставлю здесь для истории)
ну т.е нужно было корректное округление до целого, которое с лохматых годов делается прибавлением 0.5 (с учетом знака, для особо пунктуальных )
0
magicofwater
0 / 0 / 0
Регистрация: 11.06.2014
Сообщений: 5
11.06.2014, 22:47  [ТС] 19
Цитата Сообщение от uglyPinokkio Посмотреть сообщение
ну т.е нужно было корректное округление до целого, которое с лохматых годов делается прибавлением 0.5 (с учетом знака, для особо пунктуальных )
17 строка
e = d + 0.5
Так?
а если учитывать знак то все равно придется использовать функцию (модуль)? Я правильно понял?
А если придется использовать функцию, то почему бы не использовать округление до ближайшего целого? Или так памяти больше тратится или время работы увеличивается? Глупости не наговорил?
0
uglyPinokkio
326 / 229 / 55
Регистрация: 30.05.2014
Сообщений: 682
12.06.2014, 05:14 20
Цитата Сообщение от magicofwater Посмотреть сообщение
А если придется использовать функцию, то почему бы не использовать округление до ближайшего целого? Или так памяти больше тратится или время работы увеличивается? Глупости не наговорил?
Да нормальны все решения, которые дают правильный результат. Выбор - личное дело разработчика.
0
12.06.2014, 05:14
MoreAnswers
Эксперт
37091 / 29110 / 5898
Регистрация: 17.06.2006
Сообщений: 43,301
12.06.2014, 05:14

Double, int , long double
Как вычислить диапазоны типов вручную указанных в название темы?

Shot int b long double
есть задание нужно поменять местами значения бит в заданном количестве пар бит....

Требуется написать функцию long long pow(long long a, unsigned int p), которая возводит число a в степень p
Требуется написать функцию long long pow(long long a, unsigned int p), которая...


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

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

КиберФорум - форум программистов, компьютерный форум, программирование
Powered by vBulletin® Version 3.8.9
Copyright ©2000 - 2018, vBulletin Solutions, Inc.
Рейтинг@Mail.ru