The following routine generates takes a value (promoted from float or double to long double) and generates a two-part mantissa (integer and fraction parts). With optimisation above -O, the last multiply and addition are not performed. I can fix this by abusing a union (change #if 0 to #if 1).
typedef struct Double { int exponent; unsigned mantissa; /**< 100,000,000..999,999,999 */ unsigned fraction; /**< 0.1 <= fraction < 1 */ } Double; void scale(Double * out, long double value) { typedef struct { long double a; long double b; int scale; } Scale; static const Scale e3[] = { { 1e100L, 1e-100L, 100 } , { 1e200L, 1e-200L, 200 } , { 1e300L, 1e-300L, 300 } }; static const Scale e2[] = { { 1e10L, 1e-10L, 10 } , { 1e20L, 1e-20L, 20 } , { 1e30L, 1e-30L, 30 } , { 1e40L, 1e-40L, 40 } , { 1e50L, 1e-50L, 50 } , { 1e60L, 1e-60L, 60 } , { 1e70L, 1e-70L, 70 } , { 1e80L, 1e-80L, 80 } , { 1e90L, 1e-90L, 90 } }; static const Scale e1[] = { { 1e1L, 1e-1L, 1 } , { 1e2L, 1e-2L, 2 } , { 1e3L, 1e-3L, 3 } , { 1e4L, 1e-4L, 4 } , { 1e5L, 1e-5L, 5 } , { 1e6L, 1e-6L, 6 } , { 1e7L, 1e-7L, 7 } , { 1e8L, 1e-8L, 8 } , { 1e9L, 1e-9L, 9 } }; typedef struct { const Scale * scale; const int n; } Scales; static const Scales scales[] = { { e3, 3 }, { e2, 10 }, { e1, 9 } }; union { unsigned array[3]; long double value; } result = {0,0,0}; int scale = 0; int i; if (value < 0) value = -value; /* scale 0.1 <= value < 1 */ if (value != 0) for (i = 0; i < 3; ++i) { if (value >= scales[i].scale[0].a) { int j = scales[i].n; while (--j >= 0) { if (value >= scales[i].scale[j].a) { value *= scales[i].scale[j].b; scale += scales[i].scale[j].scale; break; } } } else if (value < scales[i].scale[0].b) { int j = scales[i].n; while (--j >= 0) { if (value < scales[i].scale[j].b) { value *= scales[i].scale[j].a; scale -= scales[i].scale[j].scale; break; } } } } if (value >= 1) { value *= 1e-1L; scale += 1; } else if (value < 0.1) { value *= 10; scale -= 1; } /* float values for 1e9 and 1u<<31 are exact */ printf("%.19f\t", (double)value); value *= 1e9; /* 1e9 <= value < 1e10 */ /* fix the position of the decimal point to between words * (it also does a good job of rounding) */ value += 2147483648.0f; #if 0 /* abuse union to cast (long double) to int[] - but it works */ result.value = value; out->fraction = result.array[0]; out->mantissa = result.array[1] & 0x7fffffff; #else /* this is odd, using ((int*)&value)[0] fools the optimizer * and it omits the previous 2 ops on value! */ out->fraction = ((int*)&value)[0]; out->mantissa = ((int*)&value)[1] & 0x7fffffff; #endif out->exponent = scale; } It appears that because 'value' is not used directly after the last multiply and add, these operations are dropped by the optimizer. Fails on cygwin, SuSE 8 and SuSE 10.2 gcc version 4.1.2 20061115 (prerelease) (SUSE Linux) gcc version 3.4.4 (cygming special, gdc 0.12, using dmd 0.125) gcc version 3.3.3 (SuSE Linux) -- Summary: optimizer looses ops for with aliasing Product: gcc Version: 4.1.2 Status: UNCONFIRMED Severity: normal Priority: P3 Component: c AssignedTo: unassigned at gcc dot gnu dot org ReportedBy: ajrobb at bigfoot dot com GCC build triplet: i586-suse-linux GCC host triplet: i586-suse-linux GCC target triplet: i586-suse-linux http://gcc.gnu.org/bugzilla/show_bug.cgi?id=31734