Added fahrenheit unit (#36)

Co-authored-by: Zachary Levy <zachary@sunforge.is>
Reviewed-on: #36
This commit was merged in pull request #36.
This commit is contained in:
2026-06-23 17:17:03 +00:00
parent 2acbf51637
commit 5b32f4e1ae
+101
View File
@@ -17,6 +17,11 @@ kelvins_celsius_offset :: #force_inline proc "contextless" (
return OFFSET return OFFSET
} }
@(private = "file")
FAHRENHEIT_PER_CELSIUS_DEGREE :: 9.0 / 5.0
@(private = "file")
CELSIUS_PER_FAHRENHEIT_DEGREE :: 5.0 / 9.0
// --------------------------------------------------------------------------------------------------------------------- // ---------------------------------------------------------------------------------------------------------------------
// ----- Types ------------------------ // ----- Types ------------------------
// --------------------------------------------------------------------------------------------------------------------- // ---------------------------------------------------------------------------------------------------------------------
@@ -39,6 +44,13 @@ kelvins_to_deci_kelvins :: #force_inline proc "contextless" (
return Deci_Kelvins(V){kelvins.v * DECI} return Deci_Kelvins(V){kelvins.v * DECI}
} }
@(private = "file")
kelvins_to_fahrenheit :: #force_inline proc "contextless" (
kelvins: Kelvins($V),
) -> Fahrenheit(V) where intrinsics.type_is_numeric(V) {
return celsius_to_fahrenheit(kelvins_to_celsius(kelvins))
}
//----- Decikelvins ---------------------------------- //----- Decikelvins ----------------------------------
Deci_Kelvins :: struct($V: typeid) where intrinsics.type_is_numeric(V) { Deci_Kelvins :: struct($V: typeid) where intrinsics.type_is_numeric(V) {
v: V, v: V,
@@ -70,6 +82,17 @@ celsius_to_deci_celsius :: #force_inline proc "contextless" (
return Deci_Celsius(V){degrees_celsius.v * DECI} return Deci_Celsius(V){degrees_celsius.v * DECI}
} }
@(private = "file", fast_math = {.Allow_Contract})
celsius_to_fahrenheit :: #force_inline proc "contextless" (
degrees_celsius: Celsius($V),
) -> Fahrenheit(V) where intrinsics.type_is_numeric(V) {
when intrinsics.type_is_float(V) {
return Fahrenheit(V){degrees_celsius.v * FAHRENHEIT_PER_CELSIUS_DEGREE + 32.0}
} else {
return Fahrenheit(V){degrees_celsius.v * 9 / 5 + 32}
}
}
//----- Deci Degrees Celsius ---------------------------------- //----- Deci Degrees Celsius ----------------------------------
Deci_Celsius :: struct($V: typeid) where intrinsics.type_is_numeric(V) { Deci_Celsius :: struct($V: typeid) where intrinsics.type_is_numeric(V) {
v: V, v: V,
@@ -82,12 +105,36 @@ deci_celsius_to_celsius :: #force_inline proc "contextless" (
return Celsius(V){deci_degrees_celsius.v / DECI} return Celsius(V){deci_degrees_celsius.v / DECI}
} }
//----- Degrees Fahrenheit ----------------------------------
Fahrenheit :: struct($V: typeid) where intrinsics.type_is_numeric(V) {
v: V,
}
@(private = "file")
fahrenheit_to_celsius :: #force_inline proc "contextless" (
degrees_fahrenheit: Fahrenheit($V),
) -> Celsius(V) where intrinsics.type_is_numeric(V) {
when intrinsics.type_is_float(V) {
return Celsius(V){(degrees_fahrenheit.v - 32.0) * CELSIUS_PER_FAHRENHEIT_DEGREE}
} else {
return Celsius(V){(degrees_fahrenheit.v - 32) * 5 / 9}
}
}
@(private = "file")
fahrenheit_to_kelvins :: #force_inline proc "contextless" (
degrees_fahrenheit: Fahrenheit($V),
) -> Kelvins(V) where intrinsics.type_is_numeric(V) {
return celsius_to_kelvins(fahrenheit_to_celsius(degrees_fahrenheit))
}
// --------------------------------------------------------------------------------------------------------------------- // ---------------------------------------------------------------------------------------------------------------------
// ----- Conversion Overloads ------------------------ // ----- Conversion Overloads ------------------------
// --------------------------------------------------------------------------------------------------------------------- // ---------------------------------------------------------------------------------------------------------------------
to_kelvins :: proc { to_kelvins :: proc {
deci_kelvins_to_kelvins, deci_kelvins_to_kelvins,
celsius_to_kelvins, celsius_to_kelvins,
fahrenheit_to_kelvins,
} }
to_deci_kelvins :: proc { to_deci_kelvins :: proc {
@@ -97,12 +144,18 @@ to_deci_kelvins :: proc {
to_celsius :: proc { to_celsius :: proc {
kelvins_to_celsius, kelvins_to_celsius,
deci_celsius_to_celsius, deci_celsius_to_celsius,
fahrenheit_to_celsius,
} }
to_deci_celsius :: proc { to_deci_celsius :: proc {
celsius_to_deci_celsius, celsius_to_deci_celsius,
} }
to_fahrenheit :: proc {
celsius_to_fahrenheit,
kelvins_to_fahrenheit,
}
// --------------------------------------------------------------------------------------------------------------------- // ---------------------------------------------------------------------------------------------------------------------
// ----- Tests ------------------------ // ----- Tests ------------------------
// --------------------------------------------------------------------------------------------------------------------- // ---------------------------------------------------------------------------------------------------------------------
@@ -155,3 +208,51 @@ test_deci_celsius_to_celsius :: proc(t: ^testing.T) {
testing.expect_value(t, degrees_celsius, Celsius(int){100}) testing.expect_value(t, degrees_celsius, Celsius(int){100})
} }
@(test)
test_celsius_to_fahrenheit :: proc(t: ^testing.T) {
degrees_celsius := Celsius(int){100}
degrees_fahrenheit := to_fahrenheit(degrees_celsius)
testing.expect_value(t, degrees_fahrenheit, Fahrenheit(int){212})
}
@(test)
test_fahrenheit_to_celsius :: proc(t: ^testing.T) {
degrees_fahrenheit := Fahrenheit(int){212}
degrees_celsius := to_celsius(degrees_fahrenheit)
testing.expect_value(t, degrees_celsius, Celsius(int){100})
}
@(test)
test_kelvins_to_fahrenheit :: proc(t: ^testing.T) {
kelvins := Kelvins(int){373}
degrees_fahrenheit := to_fahrenheit(kelvins)
testing.expect_value(t, degrees_fahrenheit, Fahrenheit(int){212})
}
@(test)
test_fahrenheit_to_kelvins :: proc(t: ^testing.T) {
degrees_fahrenheit := Fahrenheit(int){212}
kelvins := to_kelvins(degrees_fahrenheit)
testing.expect_value(t, kelvins, Kelvins(int){373})
}
@(test)
test_celsius_to_fahrenheit_f64 :: proc(t: ^testing.T) {
// -40 is the point where the Celsius and Fahrenheit scales coincide. It converts exactly in
// f64, so a passing equality here also confirms the 9/5 ratio constant is not lossy.
degrees_fahrenheit := to_fahrenheit(Celsius(f64){-40})
testing.expect_value(t, degrees_fahrenheit, Fahrenheit(f64){-40})
}
@(test)
test_fahrenheit_to_celsius_f64 :: proc(t: ^testing.T) {
degrees_celsius := to_celsius(Fahrenheit(f64){-40})
testing.expect_value(t, degrees_celsius, Celsius(f64){-40})
}