F# 测量单位,铸造时不丢失测量类型

发布于 2024-08-14 10:39:29 字数 261 浏览 7 评论 0原文

是否有保留单位的类型转换函数的内置版本,如果没有,我将如何制作它们?例如,使用这段代码,我如何将 intWithSecondsMeasure 转换为浮点数而不丢失度量或乘以 1.0

[<Measure>] type s
let intWithSecondsMeasure = 1<s>
let justAFloat = float intWithSecondsMeasure 

Is there built in version of the type casting functions that preserves units and if not how would I make them? So for example with this code how would I cast intWithSecondsMeasure to a float without losing the measure or multiplying by 1.0<s>?

[<Measure>] type s
let intWithSecondsMeasure = 1<s>
let justAFloat = float intWithSecondsMeasure 

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(4

梦太阳 2024-08-21 10:39:29

@kvb 提供的答案当然有效,但我不想使用 unbox 运算符进行此转换。有一种更好的内置方式,我认为应该将其编译为 NOP 到 IL(我没有检查过,但 unbox 可能最终会作为 unbox 指令在 IL 中,因此添加了运行时类型检查)。

在 F# 中进行单位转换的首选方法是 LanguagePrimitives.TypeWithMeasure (

let inline float32toFloat (x:float32<'u>) : float<'u> = 
    x |> float |> LanguagePrimitives.FloatWithMeasure

The answer provided by @kvb certainly works, but I'd prefer not to use the unbox operator for this conversion. There's a better, built in way that I think should be compiled as a NOP to IL (I haven't checked but unbox is probably going to end up as a unbox instruction in IL and thus adds a runtime type check).

The preferred way to do unit conversions in F# is LanguagePrimitives.TypeWithMeasure (MSDN).

let inline float32toFloat (x:float32<'u>) : float<'u> = 
    x |> float |> LanguagePrimitives.FloatWithMeasure
旧时光的容颜 2024-08-21 10:39:29

我不认为有内置的方法可以做到这一点,但您可以轻松定义自己的保留单位转换函数:

let float_unit (x:int<'u>) : float<'u> = unbox float x
let floatWithSecondsMeasure = float_unit intWithSecondsMeasure

I don't think that there's a built-in way to do it, but you can easily define your own unit-preserving conversion function:

let float_unit (x:int<'u>) : float<'u> = unbox float x
let floatWithSecondsMeasure = float_unit intWithSecondsMeasure
为人所爱 2024-08-21 10:39:29

我从 kvb 和 Johannes 的答案中编译了代码。

约翰内斯回答

let float32toFloat (x:int<'u>) : float<'u> = 
    x |> float |> LanguagePrimitives.FloatWithMeasure

.method public static float64  float32toFloat(int32 x) cil managed
{
  // Code size       3 (0x3)
  .maxstack  8
  IL_0000:  ldarg.0
  IL_0001:  conv.r8
  IL_0002:  ret
} // end of method Program::float32toFloat

kvb 答案并添加括号。

let float_unit (x:int<'u>) : float<'u> = unbox (float x)

.method public static float64  float_unit(int32 x) cil managed
{
  // Code size       13 (0xd)
  .maxstack  8
  IL_0000:  ldarg.0
  IL_0001:  conv.r8
  IL_0002:  box        [mscorlib]System.Double
  IL_0007:  unbox.any  [mscorlib]System.Double
  IL_000c:  ret
} // end of method Program::float_unit

kvb 答案

let float_unit (x:int<'u>) : float<'u> = unbox float x

.method public static float64  float_unit(int32 x) cil managed
{
  // Code size       19 (0x13)
  .maxstack  8
  IL_0000:  newobj     instance void Program/float_unit@4::.ctor()
  IL_0005:  call       !!0 [FSharp.Core]Microsoft.FSharp.Core.LanguagePrimitives/IntrinsicFunctions::UnboxGeneric<class [FSharp.Core]Microsoft.FSharp.Core.FSharpFunc`2<int32,float64>>(object)
  IL_000a:  ldarg.0
  IL_000b:  tail.
  IL_000d:  callvirt   instance !1 class [FSharp.Core]Microsoft.FSharp.Core.FSharpFunc`2<int32,float64>::Invoke(!0)
  IL_0012:  ret
} // end of method Program::float_unit

I compiled the code from kvb and Johannes answers.

Johannes answer

let float32toFloat (x:int<'u>) : float<'u> = 
    x |> float |> LanguagePrimitives.FloatWithMeasure

.method public static float64  float32toFloat(int32 x) cil managed
{
  // Code size       3 (0x3)
  .maxstack  8
  IL_0000:  ldarg.0
  IL_0001:  conv.r8
  IL_0002:  ret
} // end of method Program::float32toFloat

kvb answer with parentheses added.

let float_unit (x:int<'u>) : float<'u> = unbox (float x)

.method public static float64  float_unit(int32 x) cil managed
{
  // Code size       13 (0xd)
  .maxstack  8
  IL_0000:  ldarg.0
  IL_0001:  conv.r8
  IL_0002:  box        [mscorlib]System.Double
  IL_0007:  unbox.any  [mscorlib]System.Double
  IL_000c:  ret
} // end of method Program::float_unit

kvb answer

let float_unit (x:int<'u>) : float<'u> = unbox float x

.method public static float64  float_unit(int32 x) cil managed
{
  // Code size       19 (0x13)
  .maxstack  8
  IL_0000:  newobj     instance void Program/float_unit@4::.ctor()
  IL_0005:  call       !!0 [FSharp.Core]Microsoft.FSharp.Core.LanguagePrimitives/IntrinsicFunctions::UnboxGeneric<class [FSharp.Core]Microsoft.FSharp.Core.FSharpFunc`2<int32,float64>>(object)
  IL_000a:  ldarg.0
  IL_000b:  tail.
  IL_000d:  callvirt   instance !1 class [FSharp.Core]Microsoft.FSharp.Core.FSharpFunc`2<int32,float64>::Invoke(!0)
  IL_0012:  ret
} // end of method Program::float_unit
彡翼 2024-08-21 10:39:29

请参阅我对此问题的回答:

单位安全平方根

,它今天建议:

[<Measure>] 
type s
let intWithSecondsMeasure = 1<s>

let intUtoFloatU< [<Measure>] 'u>( x : int<'u> ) : float<'u> = //'
    let i = int x       //  drop the units
    let f = float i     //  cast
    box f :?> float<'u> //' restore the units

let floatWithS = intUtoFloatU intWithSecondsMeasure

See my answer to this question:

Unit-safe square roots

which suggests this today:

[<Measure>] 
type s
let intWithSecondsMeasure = 1<s>

let intUtoFloatU< [<Measure>] 'u>( x : int<'u> ) : float<'u> = //'
    let i = int x       //  drop the units
    let f = float i     //  cast
    box f :?> float<'u> //' restore the units

let floatWithS = intUtoFloatU intWithSecondsMeasure
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文