From a5547e5b1d8cd0ab1ebc538a3dadfa140261e4cd Mon Sep 17 00:00:00 2001 From: Christian Prochaska Date: Mon, 10 Dec 2018 14:18:37 +0100 Subject: [PATCH] base: improve floating point output Fixes #2876 --- repos/base/recipes/pkg/test-log/runtime | 1 + repos/base/run/log.run | 1 + repos/base/src/include/base/internal/output.h | 28 ++++++++++++++----- repos/base/src/test/log/main.cc | 2 ++ 4 files changed, 25 insertions(+), 7 deletions(-) diff --git a/repos/base/recipes/pkg/test-log/runtime b/repos/base/recipes/pkg/test-log/runtime index b1e7c4dc6..4f5469b5b 100644 --- a/repos/base/recipes/pkg/test-log/runtime +++ b/repos/base/recipes/pkg/test-log/runtime @@ -9,6 +9,7 @@ [init -> test-log] invalid hex range: [f8,08) (overflow!) [init -> test-log] negative hex char: 0xfe [init -> test-log] positive hex char: 0x02 + [init -> test-log] floating point: 1.70 [init -> test-log] multiarg string: "parent -> child.7" [init -> test-log] String(Hex(3)): 0x3 [init -> test-log] Very long messages: diff --git a/repos/base/run/log.run b/repos/base/run/log.run index 545809a61..5cabc9f12 100644 --- a/repos/base/run/log.run +++ b/repos/base/run/log.run @@ -36,6 +36,7 @@ compare_output_to { [init -> test-log] invalid hex range: [f8,08) (overflow!) [init -> test-log] negative hex char: 0xfe [init -> test-log] positive hex char: 0x02 +[init -> test-log] floating point: 1.70 [init -> test-log] multiarg string: "parent -> child.7" [init -> test-log] String(Hex(3)): 0x3 [init -> test-log] Very long messages: diff --git a/repos/base/src/include/base/internal/output.h b/repos/base/src/include/base/internal/output.h index 29a28b1a0..efbe551b8 100644 --- a/repos/base/src/include/base/internal/output.h +++ b/repos/base/src/include/base/internal/output.h @@ -114,13 +114,27 @@ static inline void out_float(T value, unsigned base, unsigned length, OUT_CHAR_F { using namespace Genode; + /* + * If the compiler decides to move a value from the FPU to the stack and + * back, the value can slightly change because of different encodings. This + * can cause problems if the value is assumed to stay the same in a chain + * of calculations. For example, if casting 6.999 to int results in 6, this + * number 6 needs to be subtracted from 6.999 in the next step and not from + * 7 after an unexpected conversion, otherwise the next cast for a decimal + * place would result in 10 instead of 9. + * By storing the value in a volatile variable, the conversion step between + * FPU and stack happens in a more deterministic way, which gives more + * consistent results with this function. + */ + T volatile volatile_value = value; + /* set flag if value is negative */ - int neg = value < 0 ? 1 : 0; + int neg = volatile_value < 0 ? 1 : 0; /* get absolute value */ - value = value < 0 ? -value : value; + volatile_value = volatile_value < 0 ? -volatile_value : volatile_value; - uint64_t integer = (uint64_t)value; + uint64_t integer = (uint64_t)volatile_value; if (neg) out_char('-'); @@ -130,14 +144,14 @@ static inline void out_float(T value, unsigned base, unsigned length, OUT_CHAR_F if (length) { do { - value -= integer; - value = value*base; + volatile_value -= integer; + volatile_value = volatile_value*base; - integer = (int64_t)value; + integer = (int64_t)volatile_value; out_char(ascii(integer)); length--; - } while (length && (value > 0.0)); + } while (length && (volatile_value > 0.0)); } } diff --git a/repos/base/src/test/log/main.cc b/repos/base/src/test/log/main.cc index 034f1d09a..a07a36a78 100644 --- a/repos/base/src/test/log/main.cc +++ b/repos/base/src/test/log/main.cc @@ -28,6 +28,8 @@ void Component::construct(Genode::Env &env) log("negative hex char: ", Hex((char)-2LL, Hex::PREFIX, Hex::PAD)); log("positive hex char: ", Hex((char) 2LL, Hex::PREFIX, Hex::PAD)); + log("floating point: ", 1700.0 / 1000); + typedef String<128> Label; log("multiarg string: ", Label(Char('"'), "parent -> child.", 7, Char('"')));