- android - 多次调用 OnPrimaryClipChangedListener
- android - 无法更新 RecyclerView 中的 TextView 字段
- android.database.CursorIndexOutOfBoundsException : Index 0 requested, 光标大小为 0
- android - 使用 AppCompat 时,我们是否需要明确指定其 UI 组件(Spinner、EditText)颜色
是否有一种简单的方法来判断特定数字是否在其浮点表示中进行四舍五入?我问的原因和我问的一个问题有关here并提出了类似的问题here , 在其他人中。
回顾一下,我试图问为什么,例如,表达式 0.5 % 0.1 不会导致大约为零,而是给出(大约)0.1。许多受访者喋喋不休地谈论大多数数字如何无法精确表示等等,但未能真正解释为什么对于某些值,当没有余数时,% 运算符的结果与零相差甚远。我花了很长时间才弄清楚发生了什么,我认为值得分享。另外,它解释了我为什么问我的问题。
如果除数以浮点格式向上舍入,但被除数却不是,则 % 运算符的结果似乎不会为零。除法算法迭代地从被除数中减去除数,直到得到负值。商是迭代次数,余数是被除数剩下的部分。可能不太清楚为什么这会导致错误(当然不是我),所以我将举一个例子。
对于 0.5 % 0.1 =(大约)0.1 的情况,0.5 可以精确表示,但 0.1 不能并且向上舍入。在二进制中,0.5 简单地表示为 0.1,但二进制中的 0.1 是 0.00011001100...重复最后 4 位数字。由于浮点格式的工作方式,在最初的 1 之后,它会被截断为 23 位(单精度)。(有关完整解释,请参阅被广泛引用的 What Every Computer Scientist Should Know About Floating-Point Arithmetic。)然后将其向上舍入,因为这更接近 0.1(十进制)值。因此,除法算法使用的值是:
0.1 0000 0000 0000 0000 0000 000 --> 0.5(十进制),并且
0.0001 1001 1001 1001 1001 1001 101 --> 0.1(十进制)
除法算法迭代次数为;
(1) 1.00000000000000000000000 - 0.000110011001100110011001101 =
(2) 0.011001100110011001100110011 - 0.000110011001100110011001101 =
(3) 0.01001100110011001100110011 - 0.000110011001100110011001101 =
(4) 0.001100110011001100110011001 - 0.000110011001100110011001101 =
(x)0.0001100110011001100110011 - 0.000110011001100110011001101 =
-0.000000000000000000000000001
如图所示,在第 4 次迭代之后,进一步相减将得到负数,因此算法停止,剩下的被除数值(以粗体显示)是余数,即小数 0.1 的近似值。
此外,表达式 0.6 % 0.1 可以按预期工作,因为 0.6 会向上舍入。表达式 0.7 % 0.1 无法按预期工作,尽管无法准确表示 0.7,但它不会向上舍入。我还没有对此进行详尽的测试,但我认为这就是正在发生的事情。这让我(终于!)想到了我的实际问题:
有谁知道判断特定数字是否会被四舍五入的简单方法?
最佳答案
让我们考虑 float a > b > 0
时的情况。每个 float 都是其 ulp 的倍数,我们可以这样写:
a = na*ulp(a). ulp(a)=2^ea
。 na 是 a 的整数有效数。 ea 是它的偏置指数。
b = nb*ulp(b). ulp(b)=2^eb
。 nb 是 b 的整数有效数。 eb 是其有偏指数。
对于标准化 float ,2^p > na >= 2^(p-1)
其中 p 是浮点精度(对于 IEEE 754 double ,p=53 位)。
因此我们可以执行(可能很大的)整数除法:na*2^(ea-eb)=nb*q+nr
从中我们推导出na*2^(ea-eb)*2^eb = nb*2^eb*q+nr*2^eb
,即a=b*q+nr*2^eb
.
换句话说,在标准化之前,nr 是浮点余数的整数有效数,eb 是其偏置指数。
由此可见,余数运算是精确的,因为显然nr <= nb,所以余数可以表示为float。因此严格来说,余数永远不会四舍五入。
当商四舍五入到最接近的整数而不是截断时,这是 IEEE 余数运算,
a=b*q+r
那么余数可以为负 r<0
在这种情况下,您感兴趣的是:
a=b*(q-1) + (b+r)
我认为这种情况下 r 为负,迫使 b+r
结果就是你所说的四舍五入。不幸的是,没有简单的方法可以在不执行该操作的情况下判断余数是否为负,除非 nb 是 2 的幂(在逐渐下溢的情况下为 2^(p-1) 或更小)。
但您似乎对具体案例感兴趣a=i/10^j
和b=1/10^j
但只有 float 近似float(i/10^j)
和float(1/10^j)
。假设 10^j 和 i 可以精确表示( double 下 j<23 且 i<=2^53),那么我们可以使用融合乘法加法来获取表示误差:
ea=fma(10^j,float(i/10^j),-i). 10^j*float(a)=10^j*a+ea.
eb=fma(10^j,float(1/10^j),-1). 10^j*float(b)=10^j*b+eb.
您有i*b=a
现在您想要比较它与浮点近似的情况,这样您就可以得到余数:
r = (a+ea/10^j)-i*(b+eb/10^j) = 1/10^j * ea - i/10^j * eb.
浮点近似可能有效,但并非总是有效:
float(float(float(b)*ea) - float(float(a)*eb))
但是,您最好再次使用 fma:
r = fma(-i,eb,ea)/10^j
余数的符号将为您提供浮点近似值的边...
这里我们稍微简化了问题,因为我们没有考虑商可能偏差超过 1 的情况。那应该没问题,因为 i < 2^53 但我们没有证明它。
这只是一种风格练习,因为我们正在用更复杂的表达式替换简单的表达式。
关于java - 如何知道以浮点格式表示时分数是否会向上舍入(re : java remainder [%] results when using fp's),我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/40061900/
我似乎对 git 存储库有权限问题。 当我 pull 入一个不是我的 Linux 用户创建的目录时,我出现了这个错误。 fatal: Unable to create '/home/---/.git/
在 Git 中,您可以将给定目录克隆到给定目录: git clone ssh://gitolite@dev.bipper.com:3687/com/bipper/kids/portal 当我运行我们
目前,如果您在分支 V2 中并执行“git pull origin V3”,它会将 V3 merge 到 V2,甚至不会发出警告或提示。这个选项可以以某种方式被阻止吗?我在这里阅读了所有类似的问题,人
我刚开始使用 Oracle 的 Coherence 缓存,我注意到这一点:如果我在缓存中放入一个 ConcurrentHashMap 对象,当我检索它时,我可以看到它被转换为一个普通的 HashMap
看起来我缺少对 git pull 和 git commit 的基本理解,假设我在分支上工作,而它在我更新时被其他开发人员更新了在本地做我的工作。我应该在发出 git pull 之前提交更改,还是应该执
好的。所以我以为我已经舔过了……但现在…… 我有一个项目,其中包含一个来自 GitHub 的小型库作为子模块。在该 super 项目的原始版本中,子模块按预期工作。 但是,我只是克隆了 super 项
使用 Visual Studio Code 中的内置 Git,我看不到将指定的远程分支 pull 入当前分支的方法。我可以这样做吗? 示例:我正在分支 myBranch 上工作,更改已 merge 到
当我尝试提交或 pull 此错误时 Bus error (core dumped) 发生了! 当我用 gdb 调试它时,(gdb git,run commit -a,where) 结果是: mucul
我对默认 Rails Rake 任务的预期用途有点困惑,想咨询一下我是否应该使用 db:reset或编写自定义 Rake 任务。没什么聪明的,只是日常管理,而且我很可能会错过一个明显的文档,因为我是
所以我做了: git reset --hard #commithash # make a bunch of changes, fixes and so on. git add -A git commi
我已使用以下命令成功部署到 firebase 托管应用: firebase init firebase deploy 在这个阶段,我正在执行 git pull 以将 repo 下 pull 到暂存服务
当尝试在 Eclipse 的 git 存储库中 pull (团队|从上下文菜单中 pull )时,出现 Could not get advertised Ref for branch refs/hea
我是一名优秀的程序员,十分优秀!