weak log calculations, possible to improve?
newbie nullzwei via gnumeric-list <[email protected]> Tue, 5 Jul 2022 19:33:56 +0200
| Newsgroups | gmane.comp.gnome.apps.gnumeric |
|---|---|
| Message-ID | <trinity-965b6544-f8ff-49d8-8d84-b2bc582bab8d-1657042436945@3c-app-gmx-bap65> |
--===============7742339317074401511==
Content-Type: text/html; charset=UTF-8
<html><head></head><body><div style="font-family: Verdana;font-size: 12.0px;"><div style="font-family: Verdana;font-size: 12.0px;">
<div> <br/>
hello @all, <br/>
<br/>
IMHO it need not be that the result of '=log( 8, 3 )' is off by two ULP. <br/>
<br/>
( it is calculated to <br/>
1.892789260714371923910E00 while '3' re-powered with that value becomes only <br/>
7.999999999999996447286E00 , and even 3 powered to the next representable double <br/>
1.892789260714372145955E00 does not! reach 8.0 but it needs the 'nextnext' representable double <br/>
1.892789260714372368000E00 as exponent to get 3 powered up to 8.0. ) <br/>
<br/>
pls. check and correct if I'm wrong ... <br/>
<br/>
( above may be one of few extreme cases? but there are more where gnumerics calculation is off by 1 ULP, e.g. log( 243, 3 ) results in '4.999999999999999...' despite the correct result '5.0' is! a representable double value. ) <br/>
<br/>
( The imprecision is 'FP typical' and - IMHO - results from calculating log( x, y ) as 'ln( x ) / ln( y )', ln( 8 ) and ln( 243 ) are undershot, ln( 3 ) is overshot, results are undershot. ) <br/>
<br/>
We can't solve cases where we'd need additional values between representable doubles, but we can try correction for cases which are uneccessary far off. <br/>
<br/>
As long as we don't find a better solution / calculation / libraries we can do the following in the gnumeric calculation: <br/>
<br/>
// edit b. - TESTING - 2022-07-03: correcting weak logs, <br/>
{ <br/>
res = gnm_log (t) / gnm_log (base); <br/>
if( gnm_abs( gnm_pow( base, nextafter( res, GNM_MAX ) ) - t ) < gnm_abs( gnm_pow( base, res ) - t ) ) <br/>
res = nextafter ( res, GNM_MAX ); <br/>
if( gnm_abs( gnm_pow( base, nextafter( res, GNM_MAX ) ) - t ) < gnm_abs( gnm_pow( base, res ) - t ) ) <br/>
res = nextafter ( res, GNM_MAX ); <br/>
if( gnm_abs( gnm_pow( base, nextafter( res, -GNM_MAX ) ) - t ) < ( gnm_abs( gnm_pow( base, res ) ) - t ) ) <br/>
res = nextafter ( res, -GNM_MAX ); <br/>
if( gnm_abs( gnm_pow( base, nextafter( res, -GNM_MAX ) ) - t ) < ( gnm_abs( gnm_pow( base, res ) ) - t ) ) <br/>
res = nextafter ( res, -GNM_MAX ); <br/>
} <br/>
// edit b. - end edit, <br/>
<br/>
it is some overhead ... but IMHO tolerable, there is no footprint in timing the gnumeric test suite. <br/>
<br/>
With a simple test field of the integers from 2 .. 20 as base and argument, and gnumeric double 'standard' we have a problem quota of about 61% where re-powering is imprecise, and can 'only' reduce that to about 48% with above 'afterburner'. That looks weak at a first glance, but it's eliminating all cases with 'big' deviation where a better solution is available in doubles, thus it is an improvement ( from 15.7899 average, 15.2028 min. 'quality' to 15.8491 average, 15.4337 min. quality ( 'quality': ~no. of correct digits ( in the re-powered value, I was too lazy to calculate 361 results with wolframalpha ) calculated similar to other tests by sthg. like '-log10( abs( result - reference ) / abs( reference ) )' ) ) <
br/>
<br/>
( 'long' has ~45% problem quota in the above scope which can be reduced to ~33% with the patch, improving quality from 19.1354 avg. / 18.6639 min. to 19.1960 avg. / 18.7404 min., needs nextafter**l** instead of nextafter. ) <br/>
<br/>
I'm aware that such can't clean up FP-weaknesses in general, it's just one small step to avoid uneccessary imprecision. <br/>
I'm aware that 'power' is FP-math too and may have weaknesses ... WIP ... perhaps one will find improvements too ... <br/>
The patch above is most likely not well programmed, I do not! write here because I'm good at programming, but because I'm good at spotting weak points, even if I sometimes slip into mistakes ... thus: whoever can do, pls. improve ... <br/>
The proposal is based on a hint from John Denker for checking and correcting roundup / rounddown fails. <br/>
One of the checks I did against too big mistakes from my side: wolframalpha: 'log( 3, 8 )' ( they use reverse operand ordering ) -> 1.8927892607143723112985813430282825628987569203956412836119648315... </div>
</div></div></body></html>
--===============7742339317074401511==
Content-Type: text/plain; charset="us-ascii"
MIME-Version: 1.0
Content-Transfer-Encoding: 7bit
Content-Disposition: inline
_______________________________________________
gnumeric-list mailing list
[email protected]
https://mail.gnome.org/mailman/listinfo/gnumeric-list
--===============7742339317074401511==--