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:
Jorijn van der Graaf 2026-11-01 03:21:41 +01:00
commit 6987033d6b
Signed by: jorijnvdgraaf
GPG key ID: 2937E59CDCC1BCFB
3 changed files with 25 additions and 3 deletions

View file

@ -6,7 +6,9 @@
// maps, a scoped enum, Required) through Value and its text, with no
// hand-written serialization. Fields the input leaves out keep their default
// member initializers, null clears an optional, and an enum also accepts its
// integer. Guards the reflection that command arguments and results rely on.
// integer. A float encodes as its shortest decimal, 0.1 rather than the
// 0.10000000149011612 it widens to, which every float watch used to show.
// Guards the reflection that command arguments and results rely on.
import std;
import Crafter.Debug.Core;
using namespace Crafter::Debug;
@ -74,6 +76,13 @@ int main() {
Check(!partial.target.has_value(), "null clears an optional");
Check(partial.mode == Game::Mode::Build, "an enum accepts its integer");
Check(Encode(0.1F).Dump() == "0.1" && Encode(-9.81F).Dump() == "-9.81" && Encode(4.0F).Dump() == "4.0",
std::format("a float reads as its shortest decimal ({}, {})", Encode(0.1F).Dump(), Encode(-9.81F).Dump()));
float tenth = 0;
DecodeContext tenthContext;
Decode(Value::Parse(Encode(0.1F).Dump()), tenth, tenthContext);
Check(tenthContext.Ok() && tenth == 0.1F && Encode(0.1).Dump() == "0.1", "and decodes to the same float; a double is unchanged");
float nan = 0;
DecodeContext nanContext;
Decode(Encode(std::numeric_limits<float>::quiet_NaN()), nan, nanContext);