fix(core): encode a float as its shortest decimal
A float was widened to double before encoding, so every float watch, argument default and result read as the double nearest it: gravity -9.81 showed as -9.8100004196167, a radius of 0.1 as 0.10000000149011612, in `get`, `help` and call results alike. Agents read these, and copy them back into `set` and `call`. Codec<float> now encodes the shortest decimal that reads back as the same float (std::to_chars), as a double. Decoding is unchanged, and so is every value: 0.1 decodes to the float 0.1f came from. A double is encoded as before. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
parent
15e0b4954d
commit
6987033d6b
3 changed files with 25 additions and 3 deletions
|
|
@ -192,7 +192,20 @@ export namespace Crafter::Debug {
|
|||
|
||||
template<std::floating_point T>
|
||||
struct Codec<T> {
|
||||
static Value Encode(T value) { return Value(static_cast<double>(value)); }
|
||||
static Value Encode(T value) {
|
||||
// A float as the shortest decimal that reads back as it: 0.1f
|
||||
// widened is 0.10000000149011612, which is what an agent would
|
||||
// otherwise read for every float.
|
||||
if constexpr (sizeof(T) < sizeof(double)) {
|
||||
if (std::isfinite(value)) {
|
||||
std::array<char, 32> text{};
|
||||
const auto written = std::to_chars(text.data(), text.data() + text.size(), value);
|
||||
double shortest = 0;
|
||||
if (written.ec == std::errc() && std::from_chars(text.data(), written.ptr, shortest).ec == std::errc()) return Value(shortest);
|
||||
}
|
||||
}
|
||||
return Value(static_cast<double>(value));
|
||||
}
|
||||
|
||||
static void Decode(const Value& value, T& out, DecodeContext& context) {
|
||||
if (value.IsNumber()) {
|
||||
|
|
|
|||
Loading…
Reference in a new issue