gpt4 book ai didi

sml - 如何在 SML 中将实数四舍五入到第 n 位小数?

转载 作者:行者123 更新时间:2023-12-04 04:24:18 24 4
gpt4 key购买 nike

SML 的新手,试图通过声明一个函数 round(n,L) 将实数四舍五入到第 n 个小数,其中 L 是一个实数列表,n 决定可以四舍五入到的第 n 个小数。

我的做法是先把实数转成字符串,然后把子串取到第n位小数,再把子串解析回实数,如果我只想把实数取到第n位小数,这个方法就可以了,但如果我有一个像 0.3456 这样的数字,我想将其四舍五入为 0.35,我的方法将无法真正实现这一点。

fun rd(_,[]) = []
|rd(a:int, x::y:real list) =
if x>0.0
then Option.getOpt(Real.fromString(String.substring(Real.toString(x),0,a+2)),0.0) :: rd(a,y)
else Option.getOpt(Real.fromString(String.substring(Real.toString(x),0,a+3)),0.0) :: rd(a,y)

预期的结果是这样的:

- rd (2, [0.1234, 0.2345, ~0.3456]);
val it = [0.12,0.23,~0.35] : real list`

但是我得到的实际输出是

val it = [0.12,0.23,~0.34] : real list

如果我想把数字四舍五入,有什么好的办法吗?

我也试过这个:

fun rd(_,[]) = []
|rd(a:int, x::y:real list) =
let
val n = real(round(x*Math.pow(10.0,real(a)))) / Math.pow(10.0,real(a))
in n::rd(a,y)
end;

但是这个解决方案会给我一个未捕获的异常溢出...

最佳答案

trying to round up a real number to nth decimal

declaring a function round(n,L), where L is a list of real numbers and n decide the nth decimal

从您在第二次尝试的解决方案中使用 Math.pow(10.0,real(a)) 来看,您似乎走上了正轨。我不明白 list 从何而来;正如 Yawar 指出的那样,尝试解决这个问题以舍入单个实数,然后递归地(使用 map)将其应用于实数列表。

所以一个函数

fun roundN (x, n) = ...

fun roundManyN (xs, n) = map (fn x => roundN (x, n)) xs

首先制作一些示例并将它们编码为测试。自从你can't compare real for equality在这些测试中,首先制作(或复制)自定义相等运算符。

fun nearlyEqual (a, b, eps) =
let val absA = Real.abs a
val absB = Real.abs b
val diff = Real.abs (a - b)
in Real.== (a, b) orelse
( if Real.== (a, 0.0) orelse
Real.== (b, 0.0) orelse
diff < Real.minNormalPos
then diff < eps * Real.minNormalPos
else diff / Real.min (absA + absB, Real.maxFinite) < eps )
end

val test_roundN_1 =
let val got = roundN (3.14159, 1)
val expected = 3.1
in nearlyEqual (got, expected, 0.1) end

val test_roundN_2 =
let val got = roundN (3.14159, 2)
val expected = 3.14
in nearlyEqual (got, expected, 0.01) end

(* rounding point *)
val test_roundN_3 =
let val got = roundN (3.14159, 3)
val expected = 3.142
in nearlyEqual (got, expected, 0.001) end

(* rounding point *)
val test_roundN_4 =
let val got = roundN (3.14159, 4)
val expected = 3.1416
in nearlyEqual (got, expected, 0.0001) end

val test_roundN_5 =
let val got = roundN (3.14159, 5)
val expected = 3.14159
in nearlyEqual (got, expected, 0.00001) end

您还有一些最终想要处理的边缘情况:

  • n 为零或负数时,或者当 n 大于分数中的位数时。
  • x 接近圆点时,例如roundN (3.1451, 2) ~> 3.15.
  • x·10ⁿ 的大小超过 int 的大小时。
  • n 太大以至于幅度变化可能会影响实数的精度时。

要获得更好的测试库,请查看 this exercism exercise 中的 teSTLib.sml(及其在 test.sml 中的使用) .

将您的第二个解决方案提取到一个函数中,并为 Math.pow (10.0, real n) 提供一个临时绑定(bind),您将获得解决方案:

fun roundN (x, n) =
let val m = Math.pow(10.0, real n)
in real (round (x * m)) / m end

this solution will give me an uncaught exception overflow

关于什么输入,我可能会问。

一个来源可能是 round : real -> int 是部分函数:有些实数不能表示为 int,例如 Real.posInfReal.negInf1e10(在 32 位 SML 上)和 1e19(在 64 位 SML 上)。为避免这种情况,请考虑使用 Real.realRound : real -> real 来避免 int 转换。

避免与 x * Math.pow(10.0, real n) 相关的错误导致不精确的一种方法是在乘法之前去除整数部分,然后添加除法后的整数部分。

关于sml - 如何在 SML 中将实数四舍五入到第 n 位小数?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/58192815/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com