[goffice] go_pow10: improve accuracy.
- From: Morten Welinder <mortenw src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [goffice] go_pow10: improve accuracy.
- Date: Sat, 6 Nov 2021 21:10:54 +0000 (UTC)
commit bcf6d9dda47e8bbe3f5e20bb46033e4db90bb407
Author: Morten Welinder <terra gnome org>
Date: Sat Nov 6 17:09:13 2021 -0400
go_pow10: improve accuracy.
pow(10,n) cannot be relied upon to return an accurate result and the
glibc people do not see that as a problem. Consequently, avoid using
pow for most cases by macro expanding our way to a 600-element table.
ChangeLog | 5 ++++
NEWS | 1 +
goffice/math/go-math.c | 65 +++++++++++++++++++++++++++++++++++++-------------
3 files changed, 55 insertions(+), 16 deletions(-)
---
diff --git a/ChangeLog b/ChangeLog
index 3965b0c6..e7e5ae3d 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,8 @@
+2021-11-06 Morten Welinder <terra gnome org>
+
+ * goffice/math/go-math.c (go_pow10): Make a much bigger table to
+ avoid depending on pow.
+
2021-08-28 Jean Brefort <jean brefort normalesup org>
* goffice/graph/gog-renderer.c (gog_renderer_draw_data_label): draw
diff --git a/NEWS b/NEWS
index ddcda622..0a774e8f 100644
--- a/NEWS
+++ b/NEWS
@@ -9,6 +9,7 @@ John Denker:
Morten:
* Introspection updates.
+ * Improve go_pow10 accuracy by avoiding pow as much as possible.
--------------------------------------------------------------------------
goffice 0.10.50:
diff --git a/goffice/math/go-math.c b/goffice/math/go-math.c
index b24ee8ec..f8a4f2bc 100644
--- a/goffice/math/go-math.c
+++ b/goffice/math/go-math.c
@@ -344,16 +344,32 @@ go_pow2 (int n)
double
go_pow10 (int n)
{
- static const double fast[] = {
- 1e-20, 1e-19, 1e-18, 1e-17, 1e-16, 1e-15, 1e-14, 1e-13, 1e-12, 1e-11,
- 1e-10, 1e-09, 1e-08, 1e-07, 1e-06, 1e-05, 1e-04, 1e-03, 1e-02, 1e-01,
- 1e+0,
- 1e+01, 1e+02, 1e+03, 1e+04, 1e+05, 1e+06, 1e+07, 1e+08, 1e+09, 1e+10,
- 1e+11, 1e+12, 1e+13, 1e+14, 1e+15, 1e+16, 1e+17, 1e+18, 1e+19, 1e+20
+ // On the assumption that the compiler's handling of double constants
+ // is correct, make a large table covering more or less the whole
+ // range. We do not want to depend on the accuracy of pow(10,n)
+ // because it is known not to be what it should be.
+
+#define TEN(n) ONE(n ## 0),ONE(n ## 1),ONE(n ## 2),ONE(n ## 3),ONE(n ## 4),ONE(n ## 5),ONE(n ## 6),ONE(n ##
7),ONE(n ## 8),ONE(n ## 9)
+ static const double pos[] = {
+#define ONE(n) 1e+0 ## n
+ TEN(00), TEN(01), TEN(02), TEN(03), TEN(04), TEN(05), TEN(06), TEN(07), TEN(08), TEN(09),
+ TEN(10), TEN(11), TEN(12), TEN(13), TEN(14), TEN(15), TEN(16), TEN(17), TEN(18), TEN(19),
+ TEN(20), TEN(21), TEN(22), TEN(23), TEN(24), TEN(25), TEN(26), TEN(27), TEN(28), TEN(29)
+#undef ONE
};
+ static const double neg[] = {
+#define ONE(n) 1e-0 ## n
+ TEN(00), TEN(01), TEN(02), TEN(03), TEN(04), TEN(05), TEN(06), TEN(07), TEN(08), TEN(09),
+ TEN(10), TEN(11), TEN(12), TEN(13), TEN(14), TEN(15), TEN(16), TEN(17), TEN(18), TEN(19),
+ TEN(20), TEN(21), TEN(22), TEN(23), TEN(24), TEN(25), TEN(26), TEN(27), TEN(28), TEN(29)
+#undef ONE
+ };
+#undef TEN
- if (n >= -20 && n <= 20)
- return (fast + 20)[n];
+ if (n >= 0 && n < (int)G_N_ELEMENTS(pos))
+ return pos[n];
+ if (n < 0 && -n < (int)G_N_ELEMENTS(neg))
+ return neg[-n];
return pow (10.0, n);
}
@@ -570,16 +586,33 @@ go_pow2l (int n)
long double
go_pow10l (int n)
{
- static const long double fast[] = {
- 1e-20L, 1e-19L, 1e-18L, 1e-17L, 1e-16L, 1e-15L, 1e-14L, 1e-13L, 1e-12L, 1e-11L,
- 1e-10L, 1e-09L, 1e-08L, 1e-07L, 1e-06L, 1e-05L, 1e-04L, 1e-03L, 1e-02L, 1e-01L,
- 1e+0L,
- 1e+01L, 1e+02L, 1e+03L, 1e+04L, 1e+05L, 1e+06L, 1e+07L, 1e+08L, 1e+09L, 1e+10L,
- 1e+11L, 1e+12L, 1e+13L, 1e+14L, 1e+15L, 1e+16L, 1e+17L, 1e+18L, 1e+19L, 1e+20L
+ // On the assumption that the compiler's handling of long double constants
+ // is correct, make a large table covering more or less the whole
+ // range of double (not long double -- that's much bigger).
+ // We do not want to depend on the accuracy of powl(10,n)
+ // because it is known not to be what it should be.
+
+#define TEN(n) ONE(n ## 0),ONE(n ## 1),ONE(n ## 2),ONE(n ## 3),ONE(n ## 4),ONE(n ## 5),ONE(n ## 6),ONE(n ##
7),ONE(n ## 8),ONE(n ## 9)
+ static const double pos[] = {
+#define ONE(n) 1e+0 ## n ## L
+ TEN(00), TEN(01), TEN(02), TEN(03), TEN(04), TEN(05), TEN(06), TEN(07), TEN(08), TEN(09),
+ TEN(10), TEN(11), TEN(12), TEN(13), TEN(14), TEN(15), TEN(16), TEN(17), TEN(18), TEN(19),
+ TEN(20), TEN(21), TEN(22), TEN(23), TEN(24), TEN(25), TEN(26), TEN(27), TEN(28), TEN(29)
+#undef ONE
+ };
+ static const double neg[] = {
+#define ONE(n) 1e-0 ## n ## L
+ TEN(00), TEN(01), TEN(02), TEN(03), TEN(04), TEN(05), TEN(06), TEN(07), TEN(08), TEN(09),
+ TEN(10), TEN(11), TEN(12), TEN(13), TEN(14), TEN(15), TEN(16), TEN(17), TEN(18), TEN(19),
+ TEN(20), TEN(21), TEN(22), TEN(23), TEN(24), TEN(25), TEN(26), TEN(27), TEN(28), TEN(29)
+#undef ONE
};
+#undef TEN
- if (n >= -20 && n <= 20)
- return (fast + 20)[n];
+ if (n >= 0 && n < (int)G_N_ELEMENTS(pos))
+ return pos[n];
+ if (n < 0 && -n < (int)G_N_ELEMENTS(neg))
+ return neg[-n];
return powl (10.0L, n);
}
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]