Форум программистов, компьютерный форум, киберфорум
С++ для начинающих
Войти
Регистрация
Восстановить пароль
Карта форума Темы раздела Блоги Сообщество Поиск Заказать работу  
 
 
Рейтинг 4.84/37: Рейтинг темы: голосов - 37, средняя оценка - 4.84
4 / 4 / 0
Регистрация: 25.06.2010
Сообщений: 106
1

непонятки

02.08.2011, 13:40. Показов 6865. Ответов 81

Author24 — интернет-сервис помощи студентам
у меня есть прога которая берет дабл и разделяет его на две сост. целое и дробное
C++
1
2
this->z = int(d);
this->p = ( d - int(d) )*100+0.5;
объясните почему без "+0.5" ничего не работает для чисел чья дробная часть( нечетная и меньше равна 9 )?
0
Programming
Эксперт
94731 / 64177 / 26122
Регистрация: 12.04.2006
Сообщений: 116,782
02.08.2011, 13:40
Ответы с готовыми решениями:

непонятки с for
Издавна мучает вопрос почему некоторые используют в цикле for ( int i = n; i < m ; i++), а другая...

непонятки с Си
вобщем вот что задали Вот что я зделал при выполнении пишет s=none(или nane-как то так)/почему...

Непонятки с WXDev C++
Народ, у кого данный компилятор, помогите разобраться. Вот программа: #include <iostream.h>...

Непонятки с итераторами
Здравствуйте, господа программисты. Пытался написать вот эту задачку, но получается что-то...

81
Заблокирован
Автор FAQ
02.08.2011, 22:36 41
Author24 — интернет-сервис помощи студентам
Просто констатация фактов
Миниатюры
непонятки  
0
Модератор
Эксперт PythonЭксперт JavaЭксперт CЭксперт С++
12458 / 7482 / 1753
Регистрация: 25.07.2009
Сообщений: 13,762
02.08.2011, 23:23 42
Цитата Сообщение от -=ЮрА=- Посмотреть сообщение
- если модуль val будет превосходить INT_MAX не будет потери точности вычислений?
Конечно будет. Замените int на int64_t, чтобы ни о чём плохом не думать... Задача-то, на сколько я понял, выдать по отдельности целыми числами целую и дробную части. У меня как-раз это и происходит (при учёте, что и та и другая помещаются в INT_MAX (INT_MIN)), а у Вас?
0
Эксперт С++
2381 / 1665 / 279
Регистрация: 29.05.2011
Сообщений: 3,399
02.08.2011, 23:51 43
Цитата Сообщение от -=ЮрА=- Посмотреть сообщение
Ну просто зачем ещё 0,5 добавлять, почти во всех постах оно сквозит, достаточно добавить 10^-5 чтобы преобразование int() было корректным
Беда-то в том, что я смогу ответить на вопрос почему именно 0.5, а вот сможешь ли ты убедительно ответить почему именно 10^-5? Почему не 0.001 или 0.000001? Ответ "потому что и так работает" выглядит слабо.
Кстати, pow(0.1,4) это не 10^-5
0
Эксперт С++
4985 / 3092 / 456
Регистрация: 10.11.2010
Сообщений: 11,169
Записей в блоге: 10
03.08.2011, 00:18 44
grizlik78,
Цитата Сообщение от grizlik78 Посмотреть сообщение
почему именно 0.5
?
0
Эксперт С++
2381 / 1665 / 279
Регистрация: 29.05.2011
Сообщений: 3,399
03.08.2011, 00:36 45
Потому, что это верхняя граница абсолютного значения ошибки представления целого числа, которую ещё можно исправить. И способ её исправления — округление до ближайшего целого.
То есть если известно, что число должно быть целым, то если истинная ошибка по модулю меньше 0.5, то достаточно просто округлить к ближайшему целому. Если ошибка больше, то её не исправить.
Алгоритм округления я показывал в функции:
Если число положительное, то надо добавить 0.5 и округлить к минус бесконечности (floor).
Если число отрицательное, то надо вычесть 0.5 и округлить к плюс бесконечности (ceil).
1
Эксперт С++
4985 / 3092 / 456
Регистрация: 10.11.2010
Сообщений: 11,169
Записей в блоге: 10
03.08.2011, 00:42 46
Цитата Сообщение от grizlik78 Посмотреть сообщение
Потому, что это верхняя граница абсолютного значения ошибки представления целого числа, которую ещё можно исправить.
Это сверх моего понимания...

Цитата Сообщение от grizlik78 Посмотреть сообщение
И способ её исправления — округление до ближайшего целого.
В какую сторону?

Цитата Сообщение от grizlik78 Посмотреть сообщение
То есть если известно, что число должно быть целым, то если истинная ошибка по модулю меньше 0.5, то достаточно просто округлить к ближайшему целому.
Это опять сверх моего понимания... (ключевые слова выделены)
0
easybudda
03.08.2011, 00:42
  #47

Не по теме:

Цитата Сообщение от grizlik78 Посмотреть сообщение
Если число отрицательное...
Вот об этом я как-то не задумался, спасибо!

0
Эксперт С++
2381 / 1665 / 279
Регистрация: 29.05.2011
Сообщений: 3,399
03.08.2011, 01:00 48
Цитата Сообщение от lazybiz Посмотреть сообщение
В какую сторону?
Для тех, кто на бронепоезде
До ближайшего целого. Этому в школе учат.
23.71 округляется до 24,
23.1 округляется до 23
23.5 округляется до 24
23.499 округляется до 23
-17.6 округляется до -18
-17.3 округляется до -17
-17.5 округляется до -18
-17.49 округляется до -17
Это называется до ближайшего целого.

Добавлено через 13 минут
Цитата Сообщение от lazybiz Посмотреть сообщение
Это сверх моего понимания...
Согласен, предложение сложное. Так бывает.
Дробные числа хранятся в памяти в усечённом виде, так как нет способа представить абсолютно любую дробь конечным количеством битов. Поэтому после умножения, к примеру, 0.11 на 100 мы получим не точно 11, а число близкое к 11, с некоторой ошибкой. Это не вызывает несогласия?
Ошибка может быть как положительной, так и отрицательной.
Кроме того, поскольку 0.11 получается у нас в результате вычитания (когда целую часть отнимаем), то ошибка эта может быть довольно существенной. В общем случае чем больше по модулю целая часть, тем больше будет модуль возможной ошибки.
В результате вместо 11 у нас может получится, к примеру, 11.07 или может 10.95, или ещё какое. Конечно, для получения настолько большой ошибки разрядности int в 32 бита не хватит, но можно ведь и более вместительный тип взять.
Так вот, пока модуль ошибки меньше чем 0.5, эту ошибку можно полностью устранить. Округлением до ближайшего целого.
0
Эксперт С++
4985 / 3092 / 456
Регистрация: 10.11.2010
Сообщений: 11,169
Записей в блоге: 10
03.08.2011, 01:16 49
Так
Цитата Сообщение от lazybiz Посмотреть сообщение
почему именно 0.5
?
Я так и не понял. И думаю не я один...

Цитата Сообщение от grizlik78 Посмотреть сообщение
Потому, что это верхняя граница абсолютного значения ошибки представления целого числа, которую ещё можно исправить.
Давай простыми словами.
0
Модератор
Эксперт PythonЭксперт JavaЭксперт CЭксперт С++
12458 / 7482 / 1753
Регистрация: 25.07.2009
Сообщений: 13,762
03.08.2011, 01:17 50
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
/* ANSI C 99 */
 
#include <stdio.h>
#include <stdlib.h>
#include <math.h>
#include <stdint.h>
 
#define signround(d) ( ( (d) < 0.0 ) ? ceil((d) - 0.5) : floor((d) + 0.5) )
#define PRECISION 3
 
int64_t lost_tail_zeros(int64_t num){
    while ( num && ! ( num % 10ll ) )
        num /= 10ll;
    return num;
}
 
int main(void){
    double val;
    
    while ( printf("> ") && scanf("%lf", &val) == 1 ){
        double tmp = signround(val * pow(10.0, PRECISION));
        int64_t iPart = (int64_t)(tmp / pow(10.0, PRECISION));
        int64_t fPart = lost_tail_zeros((int64_t)tmp % (int64_t)(pow(10.0, PRECISION)));
        printf("Int part: %lld  Fract part: %lld\n", iPart, fPart);
    }
    
    exit(0);
}
0
grizlik78
03.08.2011, 01:18
  #51

Не по теме:

Цитата Сообщение от lazybiz Посмотреть сообщение
Давай простыми словами.
А смысл? Помолчу-ка я дальше.

0
Эксперт С++
4985 / 3092 / 456
Регистрация: 10.11.2010
Сообщений: 11,169
Записей в блоге: 10
03.08.2011, 01:19 52
Цитата Сообщение от grizlik78 Посмотреть сообщение
А смысл? Помолчу-ка я дальше.
Это будет правильно с твоей стороны.
0
Эксперт С++
2381 / 1665 / 279
Регистрация: 29.05.2011
Сообщений: 3,399
03.08.2011, 01:20 53
easybudda, а зачем правые нули удаляешь? Они же значащие при заданной разрядности.
0
Модератор
Эксперт PythonЭксперт JavaЭксперт CЭксперт С++
12458 / 7482 / 1753
Регистрация: 25.07.2009
Сообщений: 13,762
03.08.2011, 01:30 54
Цитата Сообщение от grizlik78 Посмотреть сообщение
easybudda, а зачем правые нули удаляешь?
Да чёрт его знает. Мне так красивше показалось, когда 3.05 раскладывается на 3 и 5, а не на 3 и 50. Может оно и не правильно...
0
Эксперт С++
2381 / 1665 / 279
Регистрация: 29.05.2011
Сообщений: 3,399
03.08.2011, 01:32 55
Красивше, да
Но семантика-то у них 3 целых и 50 тысячных. Про то что 50 тысячных стали 5-ю сотыми из вывода уже не понять.
0
Заблокирован
Автор FAQ
03.08.2011, 09:11 56
Цитата Сообщение от grizlik78 Посмотреть сообщение
Беда-то в том, что я смогу ответить на вопрос почему именно 0.5, а вот сможешь ли ты убедительно ответить почему именно 10^-5? Почему не 0.001 или 0.000001? Ответ "потому что и так работает" выглядит слабо.
Кстати, pow(0.1,4) это не 10^-5
А теперь внимание сюрприз
C++
1
2
3
fpart = floor(val);
        spart = val - fpart;
        cout<<fpart<<" RU "<<int(100.0*spart + pow(10,-12))<<" KOP\r\n";
Скомпилируй и посмотри что и при pow(10,-12) успешно работает, я же говорил что 2,0 будет представляться как 1,9(9), ну да ладно, я к другому - если ты слышал о погрешности то добавляя 0,5 ты вносишь значительную погрешность, а для числа скажем 0,01 вносишь возмущение 5000% - и заявляешь о точности!

Далее
Цитата Сообщение от easybudda Посмотреть сообщение
int64_t iPart = (int64_t)(tmp / pow(10.0, PRECISION));
int64 9223372036854775807
double 1.79769e+308


Рассмотрим случай - я програмно ввёл целую часть 9223372036854775890 - и что тогда???
А если введу только целую часть 1.79769e+308, к какому тогда типу приводить будешь???Я пытался тебе показать что если есть тип данных с максимальным диапазоном, то не следует его целую часть преобразовывать к типу с меньшей разрядностью.
Дробная часть у меня в алгоритме изначально правильно выводилась, так что не нужно приделывать пару дополнительных колёс к коду - эту запись
C++
1
int(100.0*spart + pow(10,-12))
вводил только для копеек.
0
Эксперт С++
2381 / 1665 / 279
Регистрация: 29.05.2011
Сообщений: 3,399
03.08.2011, 11:23 57
Цитата Сообщение от -=ЮрА=- Посмотреть сообщение
Скомпилируй и посмотри что и при pow(10,-12) успешно работает
Да пожалуйста. Первая строчка вывода твоя, вторая моя.
C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
#include <iostream>
#include <cmath>
 
int main()
{
    double val = 30000.12;
    int fpart;
    double spart;
 
    fpart = floor(val);
    spart = val - fpart;
    std::cout<<fpart<<" RU "<<int(100.0*spart + pow(10,-12))<<" KOP\r\n";
    std::cout<<fpart<<" RU "<<int(100.0*spart + 0.5)<<" KOP\r\n";
    return 0;
}
Вывод для числа 30000.12:
30000 RU 11 KOP
30000 RU 12 KOP

Вот уж сюрприз сюрпризов, ага.
Так почему 10^-12 или 10^-5 или сколько надо-то?

Цитата Сообщение от -=ЮрА=- Посмотреть сообщение
а для числа скажем 0,01 вносишь возмущение 5000% - и заявляешь о точности!
Обидно, я столько написал, а оказывается впустую. Ладно хоть не на бумаге.
Цитата Сообщение от -=ЮрА=- Посмотреть сообщение
Рассмотрим случай - я програмно ввёл целую часть 9223372036854775890 - и что тогда???
Возможно для тебя и это будет сюрпризом, но double не способен сохранить точно такое целое число. То есть здесь ошибка будет уже не копейками исчисляться, а сотнями рублей.

Цитата Сообщение от -=ЮрА=- Посмотреть сообщение
А если введу только целую часть 1.79769e+308, к какому тогда типу приводить будешь???
Ежели очень хочется, то можно длинное целое из MPL взять. Только смысла нет. Здесь ошибка будет такая, сколько денег на земле никогда не было и не будет

Цитата Сообщение от -=ЮрА=- Посмотреть сообщение
Я пытался тебе показать что если есть тип данных с максимальным диапазоном, то не следует его целую часть преобразовывать к типу с меньшей разрядностью.
И здесь беда, так как для точного представления целых чисел int64_t является более вместительным, чем double.
1
paladin
286 / 187 / 7
Регистрация: 25.02.2009
Сообщений: 589
03.08.2011, 12:43 58
Мда... тяжёлый тут случай. Лучше займитесь чем-нибудь более полезным (например, класс напишите для хранения сколь угодно большого целого числа, влезающего в оперативку, затем на его основе класс рациональных чисел можно забабахать).

Если по теме, то погрешность у целых чисел наподобие int абсолютная (+/-0,5), а у вещественных (флоуты, даблы там всякие) - относительная (какие-то части процента). Это на предмете Архитектура ЭВМ должны вдалбливать, но многие интересующиеся/способные узнают эту инфу много раньше.
0
Модератор
Эксперт PythonЭксперт JavaЭксперт CЭксперт С++
12458 / 7482 / 1753
Регистрация: 25.07.2009
Сообщений: 13,762
03.08.2011, 12:51 59
Цитата Сообщение от -=ЮрА=- Посмотреть сообщение
Рассмотрим случай - я програмно ввёл целую часть 9223372036854775890 - и что тогда???
Ну до фанатизма-то доходить не нужно. Ещё раз повторяю - цель была представить целыми числами целую и дробную части, а не просто вывести на экран, при чём с сомнительной точностью. Если речь о таких больших числах - длинная арифметика в помощь. Но только здесь явно другое было нужно.

Не по теме:

Цитата Сообщение от grizlik78 Посмотреть сообщение
сколько денег на земле никогда не было и не будет
Если в монгольские тугрики пересчитать, то и long double не хватит... ;)

0
Заблокирован
Автор FAQ
03.08.2011, 13:14 60
Цитата Сообщение от grizlik78 Посмотреть сообщение
Вот уж сюрприз сюрпризов, ага.
Вбей вот так и давай забудем эту тему
C++
1
2
3
4
5
6
fpart = floor(val);
        spart = val - fpart;
        cout<<fpart<<" RU "<<100.0*spart<<" KOP\r\n";
 
        cout<<"Celay chast'"<<fpart<<"\r\n";
        cout<<"Drobn chast'"<<spart<<"\r\n";
0
03.08.2011, 13:14
IT_Exp
Эксперт
87844 / 49110 / 22898
Регистрация: 17.06.2006
Сообщений: 92,604
03.08.2011, 13:14
Помогаю со студенческими работами здесь

Непонятки со списком
Нашёл код в интернете и немного не понимаю его в некоторых местах. Объясните мне пожалуйста, зачем...

Непонятки с выводом
Задание гласит: Вычислить приближенное значение конечной суммы с точностью e:0.0005...

Непонятки с сортировкой
Добрый вечер. Практически выполнил задание, но в конце возникла проблема с сортировкой, а именно,...

Непонятки со scanf
char str_check; //строка для функции &quot;check&quot;, которая проверяет введенные данные {...


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

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