2024 Clojure 状况调查! 中分享您的想法。

欢迎!请在 关于 页面了解一些关于如何使用本网站的信息。

+1 投票
文档
重新标记

文档说明

返回 num 的有理值

但 `(rationalize 1.6)` 的结果为 `8/5`,而非预期的 `3602879701896397/2251799813685248`。没有文档说明所使用的舍入方式。

2 个答案

0 投票

选中
0 投票

为什么你期望结果是 3602879701896397/2251799813685248?

因为它代表的是文字 `1.6` 的数值,而文档中并未提及四舍五入。我已经验证了 Common Lisp
```
(print (rationalize 1.6d0))
(print (rational 1.6d0))
```
```
8/5
3602879701896397/2251799813685248
```
所以 `rationalize` 做的是相同的操作,而精确转换被称作 `rational`,但由于 Clojure 中只有一个不精确的转换函数且其行为未记录在文档中,我如何在遇到这个问题之前了解到这些呢?
`rationalize` 的工作原理是通过找到放大后的输入与10的幂的最小公倍数,并将分子和分母分别表示为该公倍数的形式,所以这始终是一个简化后的分数(在这里是基于最小公倍数2来简化16/10)。但我不知道这如何是不精确的或为什么你会期望这个结果。我不相信有任何四舍五入,这就是为什么没有提及。

编辑
四舍五入是转换为十进制的一个副作用,因为双精度字面量 `1.6` 在二进制表示中表示一个有限的分数,但在十进制中是[抱歉,不对;正在调查中]。因此,`rationalize` 寻找一个与进行双精度舍入时相同的数的分数,这在某些情况下可能很有用,但它并不明显,我只期待它在精确转换外实现,而不是代替转换。与其他语言比较
Python
```
from fractions import Fraction
print(Fraction(1.6))
```
`3602879701896397/2251799813685248`
Ruby
`puts 1.6.to_r`
`3602879701896397/2251799813685248`
Racket
```
#lang racket
(println (inexact->exact 1.6))
```
`3602879701896397/2251799813685248`
BigDecimal.valueOf
> 使用 `Double.toString(double)` 方法提供的双精度的规范字符串表示形式,将 double 转换为 BigDecimal。
Double.toString
> m 或 a 的分数部分必须打印多少位数字?分数部分必须至少有一位数字,并且在这个基础上,需要多少位以唯一区别双精度类型 adjacent values 当前的 argument value。也就是说,假设 x 是该方法为有限非零的 argument d 产生的十进制表示法表示的确切数学值。那么 d 必须是 x 最近的 double 值;如果两个 double 值与 x 等距离,那么 d 就必须是两者中的一个,并且 d 的尾数最低位必须为 0。

`rationalize` 的实现使用 `BigDecimal.valueOf` 来进行舍入。精确转换可以使用 `new BigDecimal(double)` 构造函数。
谢谢!我现在明白了。
...