-
-
Notifications
You must be signed in to change notification settings - Fork 1.6k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
IEEE 754 hexadecimal floating-point string conversions #14021
Comments
Have you consider to use the same API as for |
Simply adding an optional base parameter to class String
# unchanged
def to_f64?(whitespace : Bool = true, strict : Bool = true) : Float64?
end
# required parameter
def to_f64?(base : Int, whitespace : Bool = true, strict : Bool = true) : Float64?
case base
when 10; to_f64?(whitespace, strict)
when 16; ...
else raise ...
end
end
end Additionally the |
Just for the record, I don't think Following the IEEE hexfloat standard and naming makes totally sense, though 👍 |
What I mean is: diff --git a/src/string.cr b/src/string.cr
index 3c378bd1d..e754cf034 100644
--- a/src/string.cr
+++ b/src/string.cr
@@ -709 +709 @@ class String
- def to_f64(whitespace : Bool = true, strict : Bool = true) : Float64
+ def to_f64(whitespace : Bool = true, strict : Bool = true, base : Int = 10) : Float64 or the existing string constructor in diff --git a/src/float.cr b/src/float.cr
index a4abcf5ab..e4847da4c 100644
--- a/src/float.cr
+++ b/src/float.cr
@@ -264,4 +264,4 @@ struct Float64
# ```
- def self.new(value : String, whitespace : Bool = true, strict : Bool = true) : self
- value.to_f64 whitespace: whitespace, strict: strict
+ def self.new(value : String, whitespace : Bool = true, strict : Bool = true, base : Int = 10) : self
+ value.to_f64 whitespace: whitespace, strict: strict, base: base
end Then calls that previously rely on Speaking of which, GMP does support the "natural interpretation" for bases between 2 and 62: struct BigFloat
def initialize(str : String, *, base : Int)
if LibGMP.mpf_init_set_str(out @mpf, str, base) == -1
raise ArgumentError.new("Invalid BigFloat: #{str.inspect}")
end
end
def to_s(*, base : Int)
String.build do |io|
cstr = LibGMP.mpf_get_str(nil, out decimal_exponent, base, 0, self)
# ...
end
end
end
BigFloat.new("1000000.000", base: 16) # => 16777216.0
BigFloat.new("1000000.000", base: 2) # => 64.0
BigFloat.new("123.456", base: 25).to_s(base: 5) # => "10203.041011" |
Crystal already exposes some functionality for hexadecimal floating-point strings:
Under the hood, this is due to
LibC.strtod
andLibC.snprintf
. If we remove those funs as a result of #11952 or #12396, we might want to keep the same functionality around; but if we are doing it anyway, it seems odd that hexfloat functionality is hidden behindString#to_f64
andString#%
. So I think there should be a more straightforward API for these:Hexfloats are defined in IEEE 754-2008, section 5.12.3; they can round-trip to and from binary floating-point values with relative ease and stability, compared to decimal strings (such as when we switched from Grisu3 to Dragonbox). Some time ago I made a reference shard for this, and the standard library specs already make use of hexfloats.
Note that this isn't about supporting hexfloat literals;
0xc.ap+5
parses to12.ap.+(5)
, and there is no way to support hexfloats in the language without huge breaking changes.The text was updated successfully, but these errors were encountered: