Я пытался выяснить, будет ли использование чисел с плавающей запятой в каком-то коде на C достаточно точным для моих нужд, но после поиска и не совсем понимания того, как биты точности преобразуются в реальные числа, я решил просто написать немного кода для своего теста. случае и посмотреть, каковы были результаты.
Поплавки кажутся достаточно точными, но меня очень удивило, что на моем процессоре haswell 17 4700hq (Windows 8.1 x64, C, MSVS v120) для их работы требуется примерно на 70% больше времени. Я ожидал, что время работы будет таким же или поплавки будут работать быстрее. Но явно нет. Поэтому я отключил все оптимизации, все равно. Пробовал на отладочной версии, все те же проблемы с производительностью. AVX2 и SSE 3 показывали это.
Двойникам требуется около 197 секунд для запуска и 343 секунды для плавания.
Я просмотрел Руководство разработчика программного обеспечения для архитектур Intel® 64 и IA-32, но, учитывая его размер и отсутствие у меня опыта, я еще не нашел в нем никаких ответов на этот счет. Потом я взглянул на разборку обоих, но каких-то вопиющих отличий на мой нетренированный взгляд не заметил.
Итак, кто-нибудь знает, почему это так? Вот код, который я использовал, с единственными изменениями: с удвоения на число с плавающей запятой для всех, кроме переменной anError.
#include <errno.h>
#include <math.h>
#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
#include <string.h>
#include <time.h>
#include <sys/types.h>
#include <omp.h>
int main( void ) {
clock_t start = clock() ;
// body of a candle
double open = 0.500000 ;
double close = 0.500001 ;
double end = 1 ;
uint64_t resultCounter = 0 ;
double anError = 0 ;
while (open < end){
while(close < end){
//calc # times result is postive. Should be 0.
double res = open - close ;
if (res > 0 ) {
resultCounter++ ;
if (anError < fabs( res )) { anError = res ; }
}
close = close + 0.000001 ;
}
open = open + 0.000001 ;
close = open + .000001 ;
}
clock_t finish = clock() ;
double duration = ((double) (finish - start)) / CLOCKS_PER_SEC;
double iterations = (((end - .50000) / .000001) * ((end - .50000) / .000001)) ;
fprintf( stdout, "\nTotal processing time was %f seconds.\n", duration ) ;
fprintf( stdout, "Error is %f. Number of times results were incorrect %llu out of %f iterations.\n",
anError, resultCounter, iterations ) ;
return 0 ;
}
РЕДАКТИРОВАТЬ: причиной, по-видимому, является отсутствие f в конце чисел (спасибо, Иоахим!). По-видимому, константа с плавающей запятой без суффикса f на самом деле является двойной! Еще одна причуда Си, которая любит кусать невежественных за зад. Не уверен, в чем причина этой странности, но пожал плечами. Если кто-то хочет написать хороший ответ на это, чтобы я мог его принять, не стесняйтесь.
float
вместо этого, вы не забыли использовать, например.0.000001f
вместо простого0.000001
? Или использоватьfabsf
вместоfabs
? В противном случае компилятору придется добавить код для преобразования чисел междуfloat
иdouble
. - person Some programmer dude   schedule 04.09.2015float
тоже. - person chux - Reinstate Monica   schedule 04.09.2015double
, когда вы используетеfp:precise
. Вместо этого попробуйтеfp:fast
. - person Mysticial   schedule 04.09.2015Intel® 64 and IA-32 Architectures Software Developer’s Manual Volume 2 (2A, 2B & 2C): Instruction Set Reference, A-Z Page 3-574 MOVSS—Move Scalar Single-Precision Floating-Point Values
. Вы можете использовать числа с плавающей запятой одинарной точности в SSE, преобразование не требуется. - person EOF   schedule 05.09.2015