возможно ли/эффективно включить в работу исключение fpu или inf?

у меня такой код

петля 10 м:

 if( fz != 0.0)     
 { 
  fhx += hx/fz; 
 } 

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

Могу ли я каким-то образом избавиться от этих 10 миллионов ifs и использовать «nan/inf» или, может быть, поймать исключение и продолжить? (если fz равно нулю, мне нужно fhx += 0,0, я ничего не имею в виду, просто продолжайте? Возможно ли/эффективно включить в работу исключение fpu или inf?

(Я использую С++/mingw32)


person user2214913    schedule 06.12.2014    source источник
comment
Вы действительно работаете с кодом FPU? С SSE вы можете легко сравнивать и маскировать (вместо ветвления).   -  person harold    schedule 06.12.2014
comment
Насколько предсказуема ветвь и как часто она может привести к пропуску части? Использование исключения очень медленное, если только оно не происходит примерно никогда.   -  person harold    schedule 06.12.2014
comment
я не обязательно использую fpu, это c скомпилировано с mingw, можем ли мы использовать sse2   -  person user2214913    schedule 06.12.2014
comment
fz на самом деле является dir.z, это координата z нормализованного направления в 3d, как в трассировке лучей, так что это, вероятно, (если я не ошибаюсь) для пикселей на экваторе, но пиксельf (если я не ошибаюсь) очень редко просто целится в 0.00000 - обычно не попадает в ноль, но иногда это может быть ноль   -  person user2214913    schedule 06.12.2014
comment
пс. если вы хотите поговорить больше, вы также можете зайти на comp.lang.c (например, через группы Google) больше места для разговора   -  person user2214913    schedule 06.12.2014
comment
Что делать, если fz очень маленькое — 1e-30, 1e-100? Не взорвет ли это также ваши расчеты? Разрыв в fz=0 кажется очень странным.   -  person Alan Stokes    schedule 06.12.2014
comment
это часть расчета чего-то вроде расстояния до точки, когда вы смотрите на землю. тогда расстояние пропорционально x / z, например, 1 метр вниз z = 1 1 метр вперед делает расстояние равным 1 (x и z - координаты нормализованного вектора, поэтому на самом деле это не длина бот 1, но не так важно), когда у вас x меньше z в 100 раз, тогда расстояние x / z = 100. Когда вы смотрите на горизонт, z направления становится равным нулю, а длина становится бесконечной - это, вероятно, не увеличивает значение расстояния, я просто понял это очень большой   -  person user2214913    schedule 06.12.2014
comment
ввод - вектор направления (xy - плоскость, z + 1 - точка зенита, z-1 - антизенит (хотя я временно изменил его, поэтому z - антизенит, вектор указывает вниз) - результат этого цикла - расстояние   -  person user2214913    schedule 06.12.2014
comment
Итак ... для каждого пикселя я получил расстояние, только в очень неудачных случаях я получил точно плоское направление z для одного пикселя (поскольку я использую поплавки) и, следовательно, бесконечное расстояние, но это может случиться; / и мне нужно проверить каждый ( я знаю, что могу сделать несколько плиток, чтобы выбросить некоторые плитки, но мне интересно, что можно сделать в чистом общем случае   -  person user2214913    schedule 06.12.2014


Ответы (1)


Можно, но вряд ли это будет полезно. Маскировка тоже бесполезна в данных обстоятельствах.

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

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

Пропускная способность этого подразделения в любом случае составляет 1 на 14 циклов (на Haswell - хуже на других µarch), если только fz не является особенно "хорошим", и даже тогда это 1 на 8 циклов (опять же на Haswell). На Core2 это было больше похоже на 19 и 5, на P4 это было больше похоже (в типичной манере P4) одно деление на 71 такт, несмотря ни на что.

Хорошо предсказанная ветвь и сравнение просто исчезают в этом. На моем 4770K разница между наличием сравнения и ответвлением или отсутствием исчезла в шуме (возможно, если я прогоню его достаточное количество раз, то в конечном итоге получу статистически значимую разницу, но она будет крошечной), причем оба они выигрывают случайным образом около половину времени. Код, который я использовал для этого теста, был

global bench
proc_frame bench
    push r11
[endprolog]
    xor ecx, ecx
    mov rax, rcx
    mov ecx, -10000000
    vxorps xmm1, xmm1
    vxorps xmm2, xmm2
    vmovapd xmm3, [rel doubleone]
_bench_loop:
    imul eax, ecx, -0xAAAAAAAB  ; distribute zeroes somewhat randomly
    shr eax, 1                  ; increase to make more zeroes
    vxorps xmm0, xmm0
    vcvtsi2sd xmm0, eax
    vcomisd xmm0, xmm1          ; #
    jz _skip                    ; #
    vdivsd xmm0, xmm3, xmm0
    vaddsd xmm2, xmm0
_skip:
    add ecx, 1
    jnz _bench_loop
    vmovapd xmm0, xmm2
    pop r11
    ret
endproc_frame

Другая функция была такой же, но две строки, отмеченные знаком #, были закомментированы.

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

TL;DR особой разницы нет.

person harold    schedule 06.12.2014
comment
Интересно, у меня также есть 3 машины, и это p4 core2 и haswell; очень интересный ответ - вот пример экрана dropbox.com/s/f5bg08d1mxzht40/ мне нужно, если для каждого пикселя, хотя случаи, когда z==0,0000000, вероятно, очень редко, с другой стороны, я беру x/z mul по некоторому значению cat в int и с &1023 и использую его как поисковый индекс в текстуре - возле экватора я получил, вероятно, значения больше tnah MAX_INT, поэтому приведение его к int уже дает неправильные значения, но между прочим это - person user2214913; 06.12.2014
comment
не имеет большого значения, возможно, если я не поймаю исключение, а приведу ste inf к int, то использовать его не будет никакой разницы - ретрансляция inf будет медленнее, чем if-cecking? - person user2214913; 06.12.2014
comment
вы отключили исключение для деления на ноль или оно отключено по умолчанию? (не думайте, что это по умолчанию) Или в вашем случае появляется exception, но обработчик программатора не был определен? - person user2214913; 06.12.2014
comment
@user2214913 user2214913 по умолчанию нет видимых программистом исключений, вы просто получаете +/- бесконечность (в зависимости от знаков операндов) - person harold; 06.12.2014
comment
Я использую mingw32, и насколько я помню, у меня сбой на div на ноль. - person user2214913; 06.12.2014
comment
@ user2214913 это должно происходить только при делении целых чисел - person harold; 06.12.2014
comment
Интересно... если так, то я просто могу пропустить, если и протестировать... так что не могли бы вы сказать, поскольку я не совсем понял - вы думаете, что было бы лучше выбросить, если позволяют 1/0. превратиться в inf (затем привести его к int и использовать случайное значение, которое не наносит вреда) или лучше использовать if ? ? - person user2214913; 06.12.2014
comment
PS Я обратил внимание на неожиданное замечание, только что прокомментированное int, и оно на 10% быстрее (например, 6 мс вместо 7 мс для низкого разрешения и 23 мс для 26 мс для высокого разрешения), это хорошая информация, код также короче - person user2214913; 06.12.2014
comment
@user2214913 user2214913 Я больше не совсем понимаю, что вы имеете в виду. Кстати, если вы хотите, чтобы я посмотрел, как можно сделать код быстрее, вы можете задать новый вопрос с более полным кодом. - person harold; 06.12.2014
comment
я имею в виду, что я закомментировал, если (извините за много опечаток), и приложение оказалось на 15% быстрее - person user2214913; 06.12.2014
comment
Хорошо, проверьте, например, это stackoverflow.com/questions/27333471/ - person user2214913; 06.12.2014