-
-
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
Support half-precision floating point (Float16) #9172
Comments
Meanwhile it's probably possible to encode a small enough |
I tried, but it was very difficult to handle all cases properly (like NaN and Infinity). Most likely I was also doing something wrong as I'm not very familiar with bit operations, I based it off this gist. |
This would need compiler support, we definitely won't find time for this before 1.0. |
Actually, taking for example rust, there's no |
That's a very good idea! Looking at the rust crate, I have absolutely not idea what is going on here, however this function might be a very good starting point for a shard. |
@albertorestifo the first function is a function which uses the |
Here it is a first basic implementation as part of the CBOR library I'm working on. All the CBOR Float16 tests provided in the RFC are now passing, giving me a reasonable certainty that the conversion from the Rust code was correct. I'll now focus on finishing the CBOR library before properly extracting this into a Float16 library. |
LLVM exposes intrinsics for f16 conversion from/to f32 and f64 (f16 is actually an u16): Also see: |
I guess we can add it to the standard library, given that it's an LLVM intrinsic. I was thinking of an implementation like this: lib LibInstrinsics
fun f16tof32 = "llvm.convert.from.fp16.f32"(Int16) : Float32
fun f16tof64 = "llvm.convert.from.fp16.f64"(Int16) : Float64
fun f32tof16 = "llvm.convert.to.fp16.f32"(Float32) : Int16
fun f64tof16 = "llvm.convert.to.fp16.f64"(Float64) : Int16
end
@[Extern]
struct Float16
@value : Int16
def self.new(value : Float32)
new LibIntrinsics.f32tof16(value)
end
def self.new(value : Float64)
new LibIntrinsics.f64tof16(value)
end
private def initialize(@value : Int16)
end
def to_f32
LibIntrinsics.f16tof32(@value)
end
def to_f64
LibIntrinsics.f16tof64(@value)
end
def to_f
to_f64
end
end The idea is that With this API, if you have a C function that returns a Float16, because it's marked as lib LibSome
fun give_me_an_f16 : Float16
fun accept_f16(value : Float16)
end
# Ask a Float16 and immediately go to safe ground: Float64
f = LibSome.give_me_an_f16.to_f64
# You do the math you need with f as a Float64
# Then you convert it to Float16 at the end:
LibSome.accept_f16(Float16.new(f)) We could also add I also tried this code and it worked well: i1 = 0b0_00000_0000000001_i16
p! LibIntrinsics.f16tof64(i1)
p! i1.unsafe_as(Float16).to_f64
i2 = 0b0_00000_1111111111_i16
p LibIntrinsics.f16tof64(i2)
p! i2.unsafe_as(Float16).to_f64
i3 = 0b0_11110_1111111111_i16
p LibIntrinsics.f16tof64(i3)
p! i3.unsafe_as(Float16).to_f64 The above are some examples found in Wikipedia. Let me know if you think this is fine, I can send a PR. |
While working on an implementation of a CBOR encoder/decoder I hit a roadblock, as the protocol allows for the transmission of half-precision floating point numbers, but crystal is lacking a
Float16
type.It would be nice to have a
Float16
type in Crystal.The text was updated successfully, but these errors were encountered: