oscbyspro / Ultimathnum

Binary arithmetic reimagined in Swift
Apache License 2.0
9 stars 1 forks source link

Integer from floating-point description #67

Open oscbyspro opened 1 month ago

oscbyspro commented 1 month ago

I'm sure I'll need to losslessly parse arbitrary floating-point numbers at some point.

oscbyspro commented 1 month ago

I'll work on this for a while. Maybe I'll fix Apple's JSON decoder while I'm at it.

oscbyspro commented 1 month ago

:magic_wand: :sparkles: :sparkles: :sparkles: :sparkles: :sparkles: :sparkles: :sparkles: :sparkles: :sparkles: :sparkles: :sparkles: :sparkles: :sparkles: :sparkles: :sparkles: :sparkles: :sparkles: :sparkles: :sparkles: :sparkles: :sparkles: :sparkles:

oscbyspro commented 1 month ago

So it turns out that you can clamp the exponent to the bounds of Int, if the maximum number of characters is Int.max. But this only works if you normalize the integer, fraction, and exponent parts in a specific way. Otherwise, the saturation may introduce lossy behavior near Int.max character inputs. You'll never actually parse inputs that big, but there's a proper way of doing it with signed same-size integers. I considered using sign-magnitude to get an extra bit of space, but then I thought of the normalization thing. Signed integer buffer sizes save the day again.

oscbyspro commented 1 month ago

But a sign-magnitude exponent is simpler in practice because applying the normalization bias correctly is nontrivial.

oscbyspro commented 1 month ago

I want to support JSON, JSON5 and whatever Swift is doing.

The JSON ones work, but I just realized that Swift parses this thing: {sign}0x{hex}.{hex}p{sign}{decimal}.

I'll totally parse that too, but mixing hex and decimal is rude :(

oscbyspro commented 1 month ago

Sign and magnitude exponent saturation does not work in the case of 0x{hex}.{hex}p{decimal} since the exponent part respresents a binary multiplier. You need more bits, basically. It might be simpler to just limit the input size to some silly-big-but-small-enough number or settle on a larger exponent type. Hm.

oscbyspro commented 1 month ago

So, I bascally have a lossless strtod-as-int now. I'll just have to add some more tests and clean it up a bit. Additionally, while I'm sure I'm the last one to figure this out by myself, you can skip a bunch of comparisons by lowercasing bytes as (x|32). It's quite neat and probably by design.

oscbyspro commented 1 month ago

Hm. Theres a tricky edge case for integer sizes that aren't multiples of 4. Adding a hexadecimal digit might overflow a significand that is brought back into range by the binary exponent. Remember that strtod uses a hex-hex-bin format. I have banned silly integers for a reason in this project, but I suppose I might want to solve it regardless.

oscbyspro commented 1 month ago

I've been writing it in Swift proper with thoughts of porting it to this project, but the opposite seems wiser given that I have infrastructure I might want to evolve with the solution. Zzz. At least I found some edge cases that only applies to the former.

oscbyspro commented 1 month ago

I wonder if the exponent type in BinaryInteger/power(_:) (#53) should be UX. I think there's some merit in using Magnitude but the shift-by-1 approach doesn't scale well beyond register sizes and arbitrary integers cannot allocate beyond that. Hm.