Скорость выполнения функций ceil(),round(),floor() - страница 6

 
Nikolai Semko:

я уже об этом писал здесь

ок. как я понимаю вы пишите в рамках данного терминала и в рамках поставленной точности, перенос и работа кода на любом другом устройстве или платформе вас не интересует.

с уважением.

P.S. хороший программист должен понимать что железо и программа могут измениться и необходимо избежать ошибок в дальнейшем. при такой постановке задачи как у вас, вам возможно в будущем, будет не легко найти ошибку в функции, которую вы будете считать на тот момент непогрешимой.
      
 
Andrey Kisselyov:
ок. как я понимаю вы пишите в рамках данного терминала и в рамках поставленной точности, перенос и работа кода на любом другом устройстве или платформе вас не интересует.

с уважением.

Именно. Речь идет о MQL5 (возможно и MQL4 - не проверял).  Причем код в рамках классов или алгоритмов будет прекрасно переносится в пределах MQL. Но в C++ это тоже будет работать. У меня уже есть примеры.

 
Andrey Kisselyov:

P.S. хороший программист должен понимать что железо и программа могут измениться и необходимо избежать ошибок в дальнейшем. при такой постановке задачи как у вас, вам возможно в будущем, будет не легко найти ошибку в функции, которую вы будете считать на тот момент непогрешимой.
      
В данной ситуации невозможно даже представить изменения о которых вы говорите. Что может измениться с математикой вычисления (int)(x+0.5)? Перестанет отбрасывать дробную часть что-ли?
 
Nikolai Semko:
В данной ситуации невозможно даже представить изменения о которых вы говорите. Что может измениться с математикой вычисления (int)(x+0.5)? Перестанет отбрасывать дробную часть что-ли?

Например, будет введен новый тип данных ...

 
STARIJ:

Например, будет введен новый тип данных ...

)))  Да,  но код перестанет работать, если отменят старый тип данных.... 
 
я говорю про вот это безобразие
y=(int)(x+0.9999999999999997);

допустим взять как пример:
при изменении даже битности машины, вы перешли на 64 бита и точность машины увеличилась, ваша формула перестанет работать так как точность машины будет куда больше чем вы задаете в своей погрешности.

с уважением.

P.S. возможно возникнуть и другие варианты, при которых ваша формула будет давать сбой на некотором ряде чисел. постоянно подбирать погрешность из за перехода на другую машину или при изменениях в компиляторе, о которых вас не известили, или при изменении представления числа в машине, или из за урезания дробной части числа при компиляции в новых версиях терминала ... да мало ли что может измениться, я считаю это не очень хорошо. сделать IF или мучиться в догадках что будет дальше прописывая погрешность снова и снова...

я думаю есть над чем подумать.

 
Andrey Kisselyov:
 

...

P.S. double по определению не может быть целым, представление числа в памяти машины не изменится.

Вероятно, Вы говорите о том, что формат double не относится к целочисленным типам данных, а не о том, что в переменной типа double нельзя хранить число с целым значением? Целым то double бывает.

 

Нашел простое объяснение того, чем отличается реализованное в компьютерах округление от простейших обрезаний после суммирования. Четырнадцатилетней давности, http://delphimaster.net/view/14-10885/all:

Толик   (2003-08-13 11:04) [11]

Подобное округление принято в бухучете. Соотв., налоговая тоже применяет это округление, так что всё должно сойтись, по крайней мере на бумаге :))



DiamondShark   (2003-08-13 11:20) [12]

Ох-хо-хо... Ещё раз.
Предположим, что распределение чисел у нас близко к равномерному случайному. Тогда при "арифметическом" округлении имеем:

Цифра Погрешность
0 0
1 -1
2 -2
3 -3
4 -4
5 +5
6 +4
7 +3
8 +2
9 +1

Как легко заметить, если имеется большой массив чисел, которые потом понадобится суммировать (итого для позиций документа, сальдо по счёту и т.п.), то при "арифметическом" округлении будет накапливаться систематическая погрешность с матожиданием
0.5*10^n * 0.1 * N
где:
n -- десятичный вес разряда, до которого производится округление (до двух знаков n=-2, до целых n=0 и т.д.)
0.1 -- вероятность каждой цифры
N -- число суммируемых чисел в массиве

Для того, чтобы выровнять вероятности погрешностей надо скомпенсировать единственную нескомпенсированную (см. таблицу выше) погрешность +5. Для этого она искусственно разбивается на две равновероятные +5 -5 в зависимости от чётности предыдущей цифры.

Кстати, в слове состояния FPU есть флажок, контролирующий режим округления (арифметический/бухгалтерский).


Конец цитаты

Еще одна, http://delphimaster.net/view/15-1340952214/all: "так как обычному пользователю (менеджеру/бухгалтеру) не пояснишь, почему округление 12,5 и 13,5 - дает разный результат."


Давая пользователю "ускоренные" версии функций округления, придется настоятельно его предупреждать, что они дают повышенную погрешность при сложении. Придется тащательно оценить эту погрешность в очень разных ситуациях. Опасно это, чревато накоплением погрешности. Затрудняюсь выдумать пример, где доля загрузки процессора именно округлением окажется столь важна, что можно забыть о накапливаемых при этом ошибках.

Округление чисел. Неужели ТАК правильно???
  • delphimaster.net
3-10545           Kati                  2003-08-12 10:13  2003.09.04   обновление SQL запроса 14-10898          kalishenko            2003-08-14 20:09  2003.09.04   Win2000 Server и доступ в Интернет 1-10692           lww                   2003-08-20 10:30  2003.09.04   Как написать dll для 1С? 1-10813           koks                  2003-08-20...
 

Andrey Kisselyov:
я говорю про вот это безобразие

y=(int)(x+0.9999999999999997);

Ладно, господа отличнички, уговорили. Меняю для вас специально функцию ceil:

y=ceil(x);  ->  y=(x-(int)x>0)?(int)x+1:(int)x;
или через дефайн:
#define _ceil(x) (x-(int)x>0)?(int)x+1:(int)x

данный вариант работает на 25-50% медленнее  варианта: y=(int)(x+0.9999999999999997); Но зато максимально корректен, работает так же для отрицательных чисел и при этом все равно быстрее функции ceil(x) где-то в 3 раза

Но сам я, как простолюдин и троечник, буду использовать вариант с девятками, т.к. все ваши доводы считаю занудством и для меня, человека который долгое время программировал на ассемблере и поэтому представляющего что происходит с кодом после компиляции, является излишеством - ставить проверки там, где можно обойтись без них.

 

Вариант для положительных и отрицательных чисел:

#define _ceil(x) (x-(int)x>0)?(int)x+1:(int)x
#define _round(x) (x>0)?(int)(x+0.5):(int)(x-0.5)
#define _floor(x) (x>0)?(int)x:((int)x-x>0)?(int)x-1:(int)x
Это уже, похоже, заявка на полноценную замену функциям ceil(),round(),floor(), которая дает выигрыш в скорости в 3-4 раза.