我可以相信 ceil() 结果的实数到整数的转换吗?
假设我有一些代码,例如:
float a, b = ...; // both positive
int s1 = ceil(sqrt(a/b));
int s2 = ceil(sqrt(a/b)) + 0.1;
s1 != s2
有可能吗?我关心的是 a/b
何时是完全平方数。例如,也许a=100.0
和b=4.0
,那么ceil
的输出应该是5.00000
但是什么如果是4.99999
?
类似的问题:100.0/4.0
是否有可能计算出 5.00001
,然后 ceil
将其四舍五入为 6.00000
代码>?
我更喜欢用整数数学来做这件事,但是 sqrt
有点搞砸了这个计划。
编辑:有关如何更好地实施这一点的建议也将不胜感激! a
和 b
值是整数值,因此实际代码更像是: ceil(sqrt(float(a)/b))
< strong>编辑:根据levis501的回答,我想我会这样做:
float a, b = ...; // both positive
int s = sqrt(a/b);
while (s*s*b < a) ++s;
谢谢大家!
Suppose I have some code such as:
float a, b = ...; // both positive
int s1 = ceil(sqrt(a/b));
int s2 = ceil(sqrt(a/b)) + 0.1;
Is it ever possible that s1 != s2
? My concern is when a/b
is a perfect square. For example, perhaps a=100.0
and b=4.0
, then the output of ceil
should be 5.00000
but what if instead it is 4.99999
?
Similar question: is there a chance that 100.0/4.0
evaluates to say 5.00001
and then ceil
will round it up to 6.00000
?
I'd prefer to do this in integer math but the sqrt
kinda screws that plan.
EDIT: suggestions on how to better implement this would be appreciated too! The a
and b
values are integer values, so actual code is more like: ceil(sqrt(float(a)/b))
EDIT: Based on levis501's answer, I think I will do this:
float a, b = ...; // both positive
int s = sqrt(a/b);
while (s*s*b < a) ++s;
Thank you all!
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(4)
我认为这是不可能的。无论 sqrt(a/b) 的值是什么,它生成的都是某个值 N,我们将其用作:
由于 ceil 始终生成整数值(尽管表示为双精度值),因此我们将始终有某个值 X,第一个生成
X.0
,第二个生成X.1
。转换为int
将始终截断.1
,因此两者都会产生X
。如果 X 太大以至于 X.1 溢出了 double 的范围,那么似乎会有例外。但我不知道这在哪里是可能的。除了接近 0(不考虑溢出)之外,数字的平方根始终小于输入数字。因此,在 ceil(N)+0.1 溢出之前,在
sqrt(a/b)
中用作输入的a/b
必须已经溢出。I don't think it's possible. Regardless of the value of
sqrt(a/b)
, what it produces is some value N that we use as:Since ceil always produces an integer value (albeit represented as a double), we will always have some value X, for which the first produces
X.0
and the secondX.1
. Conversion toint
will always truncate that.1
, so both will result inX
.It might seem like there would be an exception if X was so large that X.1 overflowed the range of double. I don't see where this could be possible though. Except close to 0 (where overflow isn't a concern) the square root of a number will always be smaller than the input number. Therefore, before ceil(N)+0.1 could overflow, the
a/b
being used as an input insqrt(a/b)
would have to have overflowed already.您可能想为您的情况编写一个显式函数。例如:
这将处理奇怪的情况,即比率
a/b
的平方根在double
的精度范围内。You may want to write an explicit function for your case. e.g.:
This will handle the odd case where the square root of your ratio
a/b
is within the precision ofdouble
.浮点数的相等确实是一个问题,但恕我直言,如果我们处理整数则不是。
如果您遇到
100.0/4.0
的情况,它应该完美地计算为25.0
,因为25.0
完全可以表示为浮点数,与例如25.1
。Equality of floating point numbers is indeed an issue, but IMHO not if we deal with integer numbers.
If you have the case of
100.0/4.0
, it should perfectly evaluate to25.0
, as25.0
is exactly representable as a float, as opposite to e.g.25.1
.s1 将始终等于 s2。
C 和 C++ 标准没有过多说明数学例程的准确性。从字面上看,该标准是不可能实现的,因为 C 标准说 sqrt(x) 返回 x 的平方根,但 2 的平方根无法用浮点数精确表示。
实现具有良好性能的例程,始终返回正确舍入的结果(在舍入到最近的模式下,这意味着结果是最接近精确结果的可表示浮点数,并解决了有利于低零位的关系)是一个困难的研究问题。好的数学库的目标精度低于 1 ULP(因此返回两个最接近的可表示数字之一),也许略高于 0.5 ULP。 (ULP 是最低精度单位,即指数字段中给定特定值的低位值。)某些数学库可能比这要差得多。您必须询问您的供应商或查看文档以获取更多信息。
所以 sqrt 可能略有偏差。如果精确平方根是一个整数(在整数可以用浮点精确表示的范围内)并且库保证误差小于 1 ULP,则 sqrt 的结果必须完全正确,因为除准确结果至少还差 1 个 ULP。
同样,如果库保证错误小于 1 ULP,则 ceil 必须返回准确的结果,同样是因为准确的结果是可表示的,并且任何其他结果将至少相差 1 ULP。此外, ceil 的性质是这样的,我希望任何合理的数学库总是返回一个整数,即使库的其余部分质量不高。
对于溢出情况,如果 ceil(x) 超出了所有整数都可以精确表示的范围,则 ceil(x)+.1 比任何其他可表示的数字更接近 ceil(x),因此舍入结果在任何实现浮点标准(IEEE 754)的系统中,将 .1 添加到 ceil(x) 应该是 ceil(x)。前提是您处于默认舍入模式,即舍入到最接近的值。可以将舍入模式更改为向无穷大舍入之类的模式,这可能会导致 ceil(x)+.1 成为大于 ceil(x) 的整数。
s1 will always equal s2.
The C and C++ standards do not say much about the accuracy of math routines. Taken literally, it is impossible for the standard to be implemented, since the C standard says sqrt(x) returns the square root of x, but the square root of two cannot be exactly represented in floating point.
Implementing routines with good performance that always return a correctly rounded result (in round-to-nearest mode, this means the result is the representable floating-point number that is nearest to the exact result, with ties resolved in favor of a low zero bit) is a difficult research problem. Good math libraries target accuracy less than 1 ULP (so one of the two nearest representable numbers is returned), perhaps something slightly more than .5 ULP. (An ULP is the Unit of Least Precision, the value of the low bit given a particular value in the exponent field.) Some math libraries may be significantly worse than this. You would have to ask your vendor or check the documentation for more information.
So sqrt may be slightly off. If the exact square root is an integer (within the range in which integers are exactly representable in floating-point) and the library guarantees errors are less than 1 ULP, then the result of sqrt must be exactly correct, because any result other than the exact result is at least 1 ULP away.
Similarly, if the library guarantees errors are less than 1 ULP, then ceil must return the exact result, again because the exact result is representable and any other result would be at least 1 ULP away. Additionally, the nature of ceil is such that I would expect any reasonable math library to always return an integer, even if the rest of the library were not high quality.
As for overflow cases, if ceil(x) were beyond the range where all integers are exactly representable, then ceil(x)+.1 is closer to ceil(x) than it is to any other representable number, so the rounded result of adding .1 to ceil(x) should be ceil(x) in any system implementing the floating-point standard (IEEE 754). That is provided you are in the default rounding mode, which is round-to-nearest. It is possible to change the rounding mode to something like round-toward-infinity, which could cause ceil(x)+.1 to be an integer higher than ceil(x).