L'assertion échoue dans les chasses à zéro et/ou dénormalisée-est-le mode de zéro (par exemple, le code compilé avec -mfpmath=sse, -rapide-mathématiques, etc, mais aussi sur des tas de compilateurs et d'architectures que par défaut, tels que Intel C++ compiler) si f est dénormalisé.
Vous ne pouvez pas produire un dénormalisée flotter dans ce mode, mais le scénario est toujours possible:
a) Dénormalisée flotteur vient de la source externe.
b) Certaines bibliothèques trafiquer avec FPU modes, mais oublie (ou intentionnellement éviter) paramètre de retour après chaque appel de fonction, rendant possible pour les appelant à une inadéquation de la normalisation.
Exemple pratique qui imprime suivantes:
f = 5.87747e-39
f2 = 5.87747e-39
f = 5.87747e-39
f2 = 0
error, f != f2!
L'exemple fonctionne à la fois pour VC2010 et GCC 4.3, mais suppose que VC utilise de l'ESS pour les mathématiques en tant que par défaut et GCC utilise la FPU pour les mathématiques en tant que par défaut. L'exemple peut ne pas illustrer le problème autrement.
#include <limits>
#include <iostream>
#include <cmath>
#ifdef _MSC_VER
#include <xmmintrin.h>
#endif
template <class T>bool normal(T t)
{
return (t != 0 || fabsf( t ) >= std::numeric_limits<T>::min());
}
void csr_flush_to_zero()
{
#ifdef _MSC_VER
_MM_SET_FLUSH_ZERO_MODE(_MM_FLUSH_ZERO_ON);
#else
unsigned csr = __builtin_ia32_stmxcsr();
csr |= (1 << 15);
__builtin_ia32_ldmxcsr(csr);
#endif
}
void test_cast(float f)
{
std::cout << "f = " << f << "\n";
double d = double(f);
float f2 = float(d);
std::cout << "f2 = " << f2 << "\n";
if(f != f2)
std::cout << "error, f != f2!\n";
std::cout << "\n";
}
int main()
{
float f = std::numeric_limits<float>::min() / 2.0;
test_cast(f);
csr_flush_to_zero();
test_cast(f);
}