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

С++ для начинающих

Войти
Регистрация
Восстановить пароль
 
 
Рейтинг: Рейтинг темы: голосов - 37, средняя оценка - 4.65
Noname2512
4 / 4 / 1
Регистрация: 25.06.2010
Сообщений: 106
#1

непонятки - C++

02.08.2011, 13:40. Просмотров 4575. Ответов 81

у меня есть прога которая берет дабл и разделяет его на две сост. целое и дробное
C++
1
2
this->z = int(d);
this->p = ( d - int(d) )*100+0.5;
объясните почему без "+0.5" ничего не работает для чисел чья дробная часть( нечетная и меньше равна 9 )?
Similar
Эксперт
41792 / 34177 / 6122
Регистрация: 12.04.2006
Сообщений: 57,940
02.08.2011, 13:40     непонятки
Посмотрите здесь:

Непонятки с классами - C++
Народ, уже всё перерыл, впервые с проблемой столкнулся :( Создаю консольное приложение: файл class.h #pragma once class Order{ ...

Непонятки с bind2nd - C++
Привет. Вот к примеру есть такой код: #include <algorithm> #include <functional> #include <iostream> #include <array> ...

Непонятки со scanf - C++
char str_check; //строка для функции "check", которая проверяет введенные данные { scanf("%s",&str_check); } выскакивает...

Непонятки с wchar_t - C++
Прошу помощи: что-то не так с wchar_t. Не копирует имена файлов. Содержание program_config.txt config.cfg C:\\Projects\\abx.txt...

Непонятки с итераторами - C++
Здравствуйте, господа программисты. Пытался написать вот эту задачку, но получается что-то нехорошее. Помогите, пожалуйста! #include...

Непонятки по ссылкам - C++
Доброго времени суток! Помогите, пожалуйста разобраться. Изучаю ссылки и мне кое-что не понятно. Допустим мы объявили функцию: ...

Непонятки с синтаксисом - C++
В заголовочном файле мне встретилось такое описание класса: class source_mcast_reciever { uint16_t m_port; ...

После регистрации реклама в сообщениях будет скрыта и будут доступны все возможности форума.
-=ЮрА=-
Заблокирован
Автор FAQ
02.08.2011, 22:36     непонятки #41
Просто констатация фактов
Миниатюры
непонятки  
easybudda
Эксперт С++
9456 / 5469 / 927
Регистрация: 25.07.2009
Сообщений: 10,495
02.08.2011, 23:23     непонятки #42
Цитата Сообщение от -=ЮрА=- Посмотреть сообщение
- если модуль val будет превосходить INT_MAX не будет потери точности вычислений?
Конечно будет. Замените int на int64_t, чтобы ни о чём плохом не думать... Задача-то, на сколько я понял, выдать по отдельности целыми числами целую и дробную части. У меня как-раз это и происходит (при учёте, что и та и другая помещаются в INT_MAX (INT_MIN)), а у Вас?
grizlik78
Эксперт С++
1903 / 1435 / 109
Регистрация: 29.05.2011
Сообщений: 2,990
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
castaway
Эксперт С++
4881 / 3017 / 370
Регистрация: 10.11.2010
Сообщений: 11,076
Записей в блоге: 10
Завершенные тесты: 1
03.08.2011, 00:18     непонятки #44
grizlik78,
Цитата Сообщение от grizlik78 Посмотреть сообщение
почему именно 0.5
?
grizlik78
Эксперт С++
1903 / 1435 / 109
Регистрация: 29.05.2011
Сообщений: 2,990
03.08.2011, 00:36     непонятки #45
Потому, что это верхняя граница абсолютного значения ошибки представления целого числа, которую ещё можно исправить. И способ её исправления — округление до ближайшего целого.
То есть если известно, что число должно быть целым, то если истинная ошибка по модулю меньше 0.5, то достаточно просто округлить к ближайшему целому. Если ошибка больше, то её не исправить.
Алгоритм округления я показывал в функции:
Если число положительное, то надо добавить 0.5 и округлить к минус бесконечности (floor).
Если число отрицательное, то надо вычесть 0.5 и округлить к плюс бесконечности (ceil).
castaway
Эксперт С++
4881 / 3017 / 370
Регистрация: 10.11.2010
Сообщений: 11,076
Записей в блоге: 10
Завершенные тесты: 1
03.08.2011, 00:42     непонятки #46
Цитата Сообщение от grizlik78 Посмотреть сообщение
Потому, что это верхняя граница абсолютного значения ошибки представления целого числа, которую ещё можно исправить.
Это сверх моего понимания...

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

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

Не по теме:

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

grizlik78
Эксперт С++
1903 / 1435 / 109
Регистрация: 29.05.2011
Сообщений: 2,990
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, эту ошибку можно полностью устранить. Округлением до ближайшего целого.
castaway
Эксперт С++
4881 / 3017 / 370
Регистрация: 10.11.2010
Сообщений: 11,076
Записей в блоге: 10
Завершенные тесты: 1
03.08.2011, 01:16     непонятки #49
Так
Цитата Сообщение от lazybiz Посмотреть сообщение
почему именно 0.5
?
Я так и не понял. И думаю не я один...

Цитата Сообщение от grizlik78 Посмотреть сообщение
Потому, что это верхняя граница абсолютного значения ошибки представления целого числа, которую ещё можно исправить.
Давай простыми словами.
easybudda
Эксперт С++
9456 / 5469 / 927
Регистрация: 25.07.2009
Сообщений: 10,495
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);
}
grizlik78
03.08.2011, 01:18
  #51

Не по теме:

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

castaway
Эксперт С++
4881 / 3017 / 370
Регистрация: 10.11.2010
Сообщений: 11,076
Записей в блоге: 10
Завершенные тесты: 1
03.08.2011, 01:19     непонятки #52
Цитата Сообщение от grizlik78 Посмотреть сообщение
А смысл? Помолчу-ка я дальше.
Это будет правильно с твоей стороны.
grizlik78
Эксперт С++
1903 / 1435 / 109
Регистрация: 29.05.2011
Сообщений: 2,990
03.08.2011, 01:20     непонятки #53
easybudda, а зачем правые нули удаляешь? Они же значащие при заданной разрядности.
easybudda
Эксперт С++
9456 / 5469 / 927
Регистрация: 25.07.2009
Сообщений: 10,495
03.08.2011, 01:30     непонятки #54
Цитата Сообщение от grizlik78 Посмотреть сообщение
easybudda, а зачем правые нули удаляешь?
Да чёрт его знает. Мне так красивше показалось, когда 3.05 раскладывается на 3 и 5, а не на 3 и 50. Может оно и не правильно...
grizlik78
Эксперт С++
1903 / 1435 / 109
Регистрация: 29.05.2011
Сообщений: 2,990
03.08.2011, 01:32     непонятки #55
Красивше, да
Но семантика-то у них 3 целых и 50 тысячных. Про то что 50 тысячных стали 5-ю сотыми из вывода уже не понять.
-=ЮрА=-
Заблокирован
Автор 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))
вводил только для копеек.
grizlik78
Эксперт С++
1903 / 1435 / 109
Регистрация: 29.05.2011
Сообщений: 2,990
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.
Yurii_74
paladin
279 / 179 / 3
Регистрация: 25.02.2009
Сообщений: 592
03.08.2011, 12:43     непонятки #58
Мда... тяжёлый тут случай. Лучше займитесь чем-нибудь более полезным (например, класс напишите для хранения сколь угодно большого целого числа, влезающего в оперативку, затем на его основе класс рациональных чисел можно забабахать).

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

Не по теме:

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

MoreAnswers
Эксперт
37091 / 29110 / 5898
Регистрация: 17.06.2006
Сообщений: 43,301
03.08.2011, 13:14     непонятки
Еще ссылки по теме:

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

непонятки с указателями - C++
Добрый день! изучаем плюсы, наткнулся на одну странную ситуацию, не могу сообразить, в чём дело... :( Есть структура - Point...

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

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

Непонятки с рандомом - C++
Не могу понять из-за чего рандом в классе повторяется. Есть такой код генерации пароля... class Pas { string symbols; ...


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

Или воспользуйтесь поиском по форуму:
-=ЮрА=-
Заблокирован
Автор 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";
Yandex
Объявления
03.08.2011, 13:14     непонятки
Ответ Создать тему
Опции темы

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