From: Johannes M. <js...@su...> - 2023-07-31 13:24:57
|
Hello, this is a follow up of the mail thread with subject "Gutenprint 5.3.4: only on 32-bit failures with 'Image is too long/wide for the page' for certain PPDs" see https://sourceforge.net/p/gimp-print/mailman/gimp-print-devel/thread/5676098bc0fd4489557f650e2199ebd9%40suse.de At SUSE we did some deeper investigation of the root cause and came to the following conclusions: Rounding effects in intermediate calculations throw results off by some least significant bits with any limited-precision floating point formats. If you do: ------------------------------------------------------ floattype a = <some calculation 1>; floattype b = <some other calculation 2>; ------------------------------------------------------ where mathematically calc1 and calc2 are the same value, then ------------------------------------------------------ if (a > b) /* which imples a != b */ error(); ------------------------------------------------------ calls for unpredictable problems. On hardware 1 it might work, on hardware 2 it might not, when calc1 and calc2 happen to be implemented with different sequences of CPU instructions on hardware 1 versus hardware 2. This cannot be properly fixed with compiler settings because then calc1 and calc2 can still be implemented with different sequences of CPU instructions on hardware 1 versus hardware 2. The only way out (for what is needed in this case) is using an epsilon neighbourhood for comparisons with floating point formats. For example like the following: With an open epsilon neighbourhood of b: ------------------------------------------------------ /* consider a greater than b * only if a is significantly greater than b */ if ( a >= b + epsilon ) /* consider a less than b * only if a is significantly less than b */ if ( a <= b - epsilon ) /* consider a equals b * when a and b do not significantly differ */ if ( a < b + epsilon && a > b - epsilon ) ------------------------------------------------------ or alternatively with a closed epsilon neighbourhood of b: ------------------------------------------------------ /* consider a greater than b * only if a is significantly greater than b */ if ( a > b + epsilon ) /* consider a less than b * only if a is significantly less than b */ if ( a < b - epsilon ) /* consider a equals b * when a and b do not significantly differ */ if ( a <= b + epsilon && a >= b - epsilon ) ------------------------------------------------------ The point is to not tinker with the calculations but to only fix the comparisons. Kind Regards Johannes Meixner -- SUSE Software Solutions Germany GmbH Frankenstr. 146 - 90461 Nuernberg - Germany GF: Ivo Totev, Andrew McDonald, Werner Knoblich (HRB 36809, AG Nuernberg) |