在SML中如何将实数四舍五入到第n个小数点?
SML新手,尝试通过声明函数舍入(n,L)将实数舍入到第n个小数点,其中L是实数列表,n决定可以舍入到的第n个小数点 我的方法是先将实数转换为字符串,然后将子字符串转换为第n个小数点,然后将子字符串解析回实数,如果我只想将实数转换为第n个小数点,这很好,但是如果我有一个像0.3456这样的数字,我想将其四舍五入为0.35,我的方法就无法真正实现这一点在SML中如何将实数四舍五入到第n个小数点?,sml,Sml,SML新手,尝试通过声明函数舍入(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.ge
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;
但是这个解决方案会给我一个未捕获的异常溢出
试图将实数四舍五入到第n个小数点
声明一个函数四舍五入(n,L)
,其中L是实数列表,n决定第n个小数点
从您在第二次尝试解决方案中使用的Math.pow(10.0,real(a))
判断,您似乎已经走上了正轨。我不明白清单是怎么来的;正如Yawar所指出的,尝试并解决单个实数的舍入问题,然后递归地(使用map
)将其应用于实数列表
这是一个函数
fun roundN (x, n) = ...
fun roundManyN (xs, n) = map (fn x => roundN (x, n)) xs
首先制作一些示例,并将它们编码为测试。由于您在这些测试中失败,请首先创建(或复制)自定义相等运算符
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
此解决方案将给我一个未捕获的异常溢出
关于什么输入,我可能会问
一个来源可能是round:real->int
是一个部分函数:有一些实值不能用int表示,例如real.posInf
,real.negInf
,1e10
(在32位SML上)和1e19
(在64位SML上)。为了避免这一点,请考虑使用<代码> Real.RealSn:Realth->Reals以避免int转换。
一种避免与
x*Math.pow(10.0,实数n)
相关的错误的方法是,在乘法之前去掉整数部分,在除法之后再加上整数部分。基本库具有舍入函数,你可以用其中一个来做你需要的事情:-)我试过了,但它一直给我一个溢出异常…为什么你希望String.substring(“~0.3456”)、0,5)
产生“~0.35”
?@fishwolfs,这是因为递归而不是因为舍入。我建议先编写一个小数舍入函数,它可以处理单个数字。然后只需使用List.map
将其应用于real列表。
fun roundN (x, n) =
let val m = Math.pow(10.0, real n)
in real (round (x * m)) / m end