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

Умножение и деление - C++

Восстановить пароль Регистрация
 
 
Рейтинг: Рейтинг темы: голосов - 12, средняя оценка - 4.58
CEBEP
105 / 105 / 9
Регистрация: 21.03.2010
Сообщений: 437
08.07.2013, 17:36     Умножение и деление #1
Представьте себе числовой массив первым элементом равным begin. Если далее к нему мы будем прибавлять step пока не достигнем end то сформируем массив. Таким образом размер такого массива будет вычисляться по формуле
C++
1
size = static_cast<size_t>((end - begin) / step) + 1;
а последний элемент можно будет найти по формуле
C++
1
last = min + step * (size - 1);
Всё бы ничего но иногда отрезок делится на step целое число раз начинаются проблемы: из-за погрешности операций над вещественными числами в каком-то бородатом знаке после запятой результат деления оказывается чуть меньше целого числа, т. е., например, если begin = 1.0, end = 3.0, step = 1.0, при делении может оказаться что (end - begin) / step = 1.99999999999, в результате мы получим size = 2, хотя в массиве должны быть 1.0, 2.0 и 3.0. Безграмотное решение:
C++
1
size = static_cast<size_t>((end - begin) / step + 1e-8) + 1;
Вопрос к знатокам всяких там <cfloat> и <limits>: как это сделать грамотно?
Similar
Эксперт
41792 / 34177 / 6122
Регистрация: 12.04.2006
Сообщений: 57,940
08.07.2013, 17:36     Умножение и деление
Посмотрите здесь:

C++ Деление на 0
C++ Вычитание, умножение, деление столбиком
деление на 0 C++
C++ Умножение и деление целого числа
C++ Деление
После регистрации реклама в сообщениях будет скрыта и будут доступны все возможности форума.
Nomadd
14 / 9 / 0
Регистрация: 12.07.2012
Сообщений: 82
08.07.2013, 17:59     Умножение и деление #2
Но почему не используется целочисленный тип?
CEBEP
105 / 105 / 9
Регистрация: 21.03.2010
Сообщений: 437
08.07.2013, 18:02  [ТС]     Умножение и деление #3
какой целочисленный тип? о чем вы? Мне нужно описать произвольный интервал данных. от e до pi к примеру... с шагом log(0.1)
Avyyakta
0 / 0 / 0
Регистрация: 08.07.2013
Сообщений: 19
08.07.2013, 18:05     Умножение и деление #4
Цитата Сообщение от CEBEP Посмотреть сообщение
...
C++
1
size = static_cast<size_t>((end - begin) / step) + 1;
...
C++
1
size = static_cast<size_t>((end - begin) / step + 1e-8) + 1;
Вопрос к знатокам всяких там <cfloat> и <limits>: как это сделать грамотно?
C++
1
size = (size_t)((end - begin) / step) + 1;
Кто же тебя надоумил кастовать по статик? Простое преобразование должно решить твою проблему.
CEBEP
105 / 105 / 9
Регистрация: 21.03.2010
Сообщений: 437
08.07.2013, 18:11  [ТС]     Умножение и деление #5
Цитата Сообщение от Avyyakta Посмотреть сообщение
Простое преобразование должно решить твою проблему.
типа (int)? чем от отличается? в с++ он просто вызывает последовательно несколько кастов.
zenw
154 / 110 / 3
Регистрация: 12.06.2013
Сообщений: 168
08.07.2013, 18:12     Умножение и деление #6
Цитата Сообщение от Avyyakta Посмотреть сообщение
Кто же тебя надоумил кастовать по статик? Простое преобразование должно решить твою проблему.
Гражданин, пройдите в сторону чистого С. В топике про С++ вам не место.
Avyyakta
0 / 0 / 0
Регистрация: 08.07.2013
Сообщений: 19
08.07.2013, 18:33     Умножение и деление #7
Цитата Сообщение от zenw Посмотреть сообщение
Гражданин, пройдите в сторону чистого С. В топике про С++ вам не место.
Отчего же?
Просто парень не знает, что статик каст не преобразует данные.
Кастование создано для того чтобы изменять области видимости компилятором, а не для преобразования данных.
И size_t это вовсе не int (по крайней мере в C++), хотя также целочисленно.
CEBEP
105 / 105 / 9
Регистрация: 21.03.2010
Сообщений: 437
08.07.2013, 19:04  [ТС]     Умножение и деление #8
Цитата Сообщение от Avyyakta Посмотреть сообщение
Кастование создано для того чтобы изменять области видимости компилятором
действительно не знаю. Чем это отличается от приведения типов?

Добавлено через 1 минуту
обычно касты используют при работе с указателями, я думал тут дело в том, что при работе с переменными отличие кастов от приведения типов в стиле си не существенно. однако, я много раз видел, например в qt, чтобы там приводили именно переменные к нужному типу с помощью кастов

Добавлено через 2 минуты
проверил, если написать
C
1
s = (size_t)((end - begin) / step) + 1;
то проблема не решается.
Avyyakta
0 / 0 / 0
Регистрация: 08.07.2013
Сообщений: 19
08.07.2013, 19:14     Умножение и деление #9
Цитата Сообщение от CEBEP Посмотреть сообщение
действительно не знаю. Чем это отличается от приведения типов? насчет int - просто был не уверен что в си есть size_t. Везде где я работал он просто unsigned int...
Все зависит от компилятора... В моем любимои GNU С++ ver. 4 size_t это unsigned long.
Цитата Сообщение от CEBEP Посмотреть сообщение
обычно касты используют при работе с указателями, я думал тут дело в том, что при работе с переменными отличие кастов от приведения типов в стиле си не существенно. однако, я много раз видел, например в qt, чтобы там приводили именно переменные к нужному типу с помощью кастов
В Qt данные преобразуются до кастов, а указывая тип в кастовании просто определяют размер участка памяти к котрому обращаются. Это часто применяется в Qt. Да и кастование в Qt в основном применяется для указателей, а не для результатов вычислений.

Добавлено через 3 минуты
Цитата Сообщение от CEBEP Посмотреть сообщение
проверил, если написать
C
1
s = (size_t)((end - begin) / step) + 1;
то проблема не решается.
Извини забыл округление
C
1
s = (size_t)((end - begin) / step + 0.5) + 1;
Щто там у тебя за компилятор такой?
CEBEP
105 / 105 / 9
Регистрация: 21.03.2010
Сообщений: 437
08.07.2013, 20:41  [ТС]     Умножение и деление #10
Цитата Сообщение от Avyyakta Посмотреть сообщение
Щто там у тебя за компилятор такой?
MinGW,
Как-раз хотел в начале написать... округление тут не при чем. проблема не связана с округлением. При параметрах min = 0.0, max = 2.0, step = 1.1, last должно быть 1.1, в данной постановке оно получится 2.2
Olivеr
 Аватар для Olivеr
411 / 407 / 13
Регистрация: 06.10.2011
Сообщений: 830
08.07.2013, 21:03     Умножение и деление #11
C++
1
2
3
4
5
6
7
8
9
10
#include <iostream>
using namespace std;
 
int main(void)
{
    double begin = 1.0, end = 3.0, step = 1.0;
    int size = (end - begin) / step + 1.0;
    cout << size;
    return 0;
}
3
CEBEP
105 / 105 / 9
Регистрация: 21.03.2010
Сообщений: 437
08.07.2013, 21:04  [ТС]     Умножение и деление #12
Цитата Сообщение от Olivеr Посмотреть сообщение
3
ну да, но это просо прецедент. просто в данном случае погрешность положительная и число (end - begin) / step оказалось немного больше двух. При минимуме = 1e-4, максимуме = 1., и шаге = 5.0e-6 результат вычисления неверный
Olivеr
 Аватар для Olivеr
411 / 407 / 13
Регистрация: 06.10.2011
Сообщений: 830
08.07.2013, 21:10     Умножение и деление #13
CEBEP, в смысле? Вы писали
Цитата Сообщение от CEBEP Посмотреть сообщение
в результате мы получим size = 2, хотя в массиве должны быть 1.0, 2.0 и 3.0.
Разве не 1.0, 2.0, 3.0 ?

Добавлено через 5 минут
Цитата Сообщение от CEBEP Посмотреть сообщение
ну да, но это просо прецедент. просто в данном случае погрешность положительная и число (end - begin) / step оказалось немного больше двух. При минимуме = 1e-4, максимуме = 1., и шаге = 5.0e-6 результат вычисления неверный
у вас какой результат получается?
CEBEP
105 / 105 / 9
Регистрация: 21.03.2010
Сообщений: 437
08.07.2013, 21:11  [ТС]     Умножение и деление #14
Цитата Сообщение от Olivеr Посмотреть сообщение
у вас какой результат получается?
0.999995
Olivеr
 Аватар для Olivеr
411 / 407 / 13
Регистрация: 06.10.2011
Сообщений: 830
08.07.2013, 21:13     Умножение и деление #15
Ищите проблему у себя
C++
1
2
3
4
5
6
7
8
9
10
11
12
#include <iostream>
using namespace std;
 
int main(void)
{
    double begin = 1e-4, end = 1.0, step = 5.0e-6;
    int size = (end - begin) / step + 1.0;
    cout << "int size = " << size;
    double x = (1.0-1.0/10000.0) / (5.0 / 1000000.0) + 1.0;
    cout << "\ndoble size = " << x;
    return 0;
}
Миниатюры
Умножение и деление  
CEBEP
105 / 105 / 9
Регистрация: 21.03.2010
Сообщений: 437
08.07.2013, 21:22  [ТС]     Умножение и деление #16
Цитата Сообщение от Olivеr Посмотреть сообщение
double x = (1.0-1.0/10000.0) / (5.0 / 1000000.0) + 1.0;
действительно у нас различные результаты. Но ведь мы говорим об ошибках, то есть о случайных явлениях. мне удалось подобрать отношение с отрицательной погрешностью на своём компиляторе и своей машине, на вашей скорее всего комбинация другая. результат работы вашего кода у меня:
Код
int size =  199980 
doble size =  199981
Olivеr
 Аватар для Olivеr
411 / 407 / 13
Регистрация: 06.10.2011
Сообщений: 830
08.07.2013, 21:30     Умножение и деление #17
CEBEP, ну так сделайте
C++
1
2
3
4
5
6
7
8
9
10
11
12
#include <iostream>
using namespace std;
 
int main(void)
{
    double begin = 1e-4, end = 1.0, step = 5.0e-6;
    double x = (end - begin) / step + 1.0;
    int size = x;
    cout << "int size = " << size;
    cout << "\ndouble size = " << x;
    return 0;
}
и не заморачивайтесь)

Добавлено через 1 минуту
Максимальная относительная погрешность для double - 2^-52 если что
CEBEP
105 / 105 / 9
Регистрация: 21.03.2010
Сообщений: 437
08.07.2013, 21:40  [ТС]     Умножение и деление #18
C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
int main(void)
{
    int i = 0;
    while (++i != 320)
    {
        double begin = rand() * 1.0 / rand(), end = begin + rand() * 1.0 / rand(), step = (end - begin) / rand();
        double x = (end - begin) / step + 1.0;
        int size = x;
        if (size != x)
        {
            cout << begin << ' ' << end << ' ' << step << ' ' << x << ' ' << size << endl;
        }
    }
}
вот что у меня вывалилось... думаю, у вас тоже не будет пустой списко
Код
0.250713   1.53092   0.000684968   1870   1869 
0.308038   0.580965   3.97389e-05   6869   6868 
2.38421   2.91368   2.01257e-05   26309   26309 
1.258   3.93092   0.000178851   14946   14946 
0.234934   1.35681   4.6073e-05   24351   24350 
0.333733   1.18437   0.000185082   4597   4597 
0.250319   1.34661   6.15654e-05   17808   17808 
0.169182   0.459236   3.04871e-05   9515   9514 
0.85904   1.1179   9.10424e-06   28434   28434 
1.48292   18.3219   0.000769571   21882   21882 
4.12   4.23951   4.44776e-06   26870   26869 
1.66916   7.456   0.000358562   16140   16139 
0.76313   2.32099   0.00012434   12530   12530 
0.136911   0.610822   1.83515e-05   25825   25825 
4.50838   4.79866   3.80598e-05   7628   7627 
2.17057   126.298   0.00402581   30834   30833
Добавлено через 3 минуты
C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
int main(void)
{
    int i = 0;
    int right(0);
    int wrong(0);
    while (++i != 320)
    {
        double begin = rand() * 1.0 / rand(), end = begin + rand() * 1.0 / rand(), step = (end - begin) / rand();
        double x = (end - begin) / step + 1.0;
        int size = x;
        if (size != x)
        {
            cout << begin << ' ' << end << ' ' << step << ' ' << x << ' ' << size;
            ++wrong;
        }
        else
        {
            cout << "all right";
            ++right;
        }
    }
    cout << right << ' ' << wrong << endl;
}
счетчики выпали 247 72
Olivеr
 Аватар для Olivеr
411 / 407 / 13
Регистрация: 06.10.2011
Сообщений: 830
08.07.2013, 21:43     Умножение и деление #19
Поправил
Цитата Сообщение от CEBEP Посмотреть сообщение
if (size != x)
на
C++
1
if (size != static_cast<int>(x) )
и пусто

Добавлено через 57 секунд
all right
all right
all right
all right
all right
319 0
MoreAnswers
Эксперт
37091 / 29110 / 5898
Регистрация: 17.06.2006
Сообщений: 43,301
08.07.2013, 21:52     Умножение и деление
Еще ссылки по теме:

сложение и вычитание, умножение и деление, сравнение сумм C++
Деление на 6 C++
создать библиотеку из 5 функций: сложение, вычетание, деление, умножение и выделение корня C++

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

Или воспользуйтесь поиском по форуму:
CEBEP
105 / 105 / 9
Регистрация: 21.03.2010
Сообщений: 437
08.07.2013, 21:52  [ТС]     Умножение и деление #20
всё правильно)) оба ошиблись одинаково. то есть если было 3.9999999999999 он его при инициализации size привёл к 3 и при касте так же привёл к 3

Добавлено через 7 минут
это как-раз доказывает, что static_cast и механизм приведения double к int в данном случае работают идентично
Yandex
Объявления
08.07.2013, 21:52     Умножение и деление
Ответ Создать тему
Опции темы

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