为什么有些C数学表达式需要将常量显式标记为浮点数?

时间:2013-08-14 08:10:21

标签: objective-c c math

所以我刚刚在我的代码中发现了这个错误,我想知道我不理解的规则。

我有一个float变量logDiff,目前包含一个非常小的数字。我想看看它是否大于常数表达式(第12位的80%)。我多年前在代码完成中阅读过,只是将计算常量保留为最简单的形式以便于阅读,而编译器(XCode 4.6.3)无论如何都会内联它们。我有,

            if ( logDiff > 1/12 * .8 ) {  

我假设.8并且分数都评估为正确的数字。看起来合法:

(lldb) expr (float) 1/12 * .8
(double) $1 = 0.0666666686534882
(lldb) expr logDiff
(float) $2 = 0.000328541

但它始终错误地评估为true。即使我把周围的东西弄得乱七八糟。

(lldb) expr logDiff > 1/12 * .8
(bool) $4 = true
(lldb) expr logDiff > (1/12 * .8)
(bool) $5 = true
(lldb) expr logDiff > (float)(1/12 * .8)
(bool) $6 = true

我发现我必须明确拼写其中至少一个作为花车以获得正确的结果,

(lldb) expr logDiff > (1.f/12.f * .8f)
(bool) $7 = false
(lldb) expr logDiff > (1/12.f * .8)
(bool) $8 = false
(lldb) expr logDiff > (1./12 * .8f)
(bool) $11 = false
(lldb) expr logDiff > (1./12 * .8)
(bool) $12 = false

但我最近阅读a popular style guide明确地避开了这些更高级的数字文字,显然是根据我的假设,编译器会比我聪明并且做我的意思。

如果他们可能需要成为浮点数,我是否应该像1.f一样拼写我的数字常量?听起来很迷信。帮助我理解为什么以及什么时候需要?

4 个答案:

答案 0 :(得分:4)

表达式1/12整数除法。这意味着结果将被截断为零。

执行(float) 1/12时,将其作为浮点数转换,整个表达式成为浮点表达式。

答案 1 :(得分:1)

在C int/int中提供int。如果你没有明确地告诉编译器将至少一个转换为float,它将进行除法并向下舍入到最近的int(在这种情况下为0)。

我注意到链接样式指南实际上是说除非必要,否则避免将数字设为特定类型。在这种情况下,您需要的是编译器进行某些类型转换所需的内容

答案 2 :(得分:1)

1 / 4之类的表达式被视为整数除法,因此没有小数精度。在这种特定情况下,结果将是0。您可以将此视为int / int隐含int

  

我是否总是将我的数字常量拼写为1.f,如果它们可能需要浮点数?听起来很迷信。帮助我理解为什么以及什么时候需要?

这不是迷信,你告诉编译器这些是类型文字(浮动作为一个例子),编译器将处理它们上的所有操作。

此外,你可以施放一个表达式。请考虑以下事项:

float result = ( float ) 1 / 4;

...我正在将1投射为浮点数,因此float / int的结果将为float。请参阅数据类型操作优先级(或促销)。

答案 3 :(得分:1)

这很简单。默认情况下,数字值被视为int。 有数学表达的地方并不重要。但是如果出现分歧,它会让你发疯。 (int) 1 / (int) 12不是(float) 0.08333,而是(int) 01/12.0将评估为(float) 0.83333

旁注:当你再使用int时浮动,然后再有一个陷阱等着你。那是你比较平等的价值的时候。

float f = 12/12.0f; 
if (f = 1) ... // this may not work out. Never expect a float to be of a specific value. They can vary slightly. 

更好的是:

if (abs(f - 1) < 0.0001) ... // this way yoru comparison is fuzzy enough for the variances that float values may come with.