是否有一种编程语言,其中1/6的行为与1.0 / 6.0相同?


11

几天前,当我使用C ++编程时,我犯了这个错误(我有这样做的历史!)。在我的代码的一部分中,我的值为1/6,我期望为0.16666666666,事实并非如此。众所周知,结果为0-C,C ++,Java,Python的行为均相同。

我将其发布在我的Facebook页面上,现在就是否存在1/6与行为相同的编程语言存在争议1.0/6.0


5
哈斯克尔。1/6 = 0.16666666666666666
t123 2012年

PowerShell生成0.166666666666667,这让我感到惊讶,因为1是整数。我敢打赌,还有其他.NET语言可以产生您期望的价值。
JohnL 2012年

从理论上讲,它们的数量是无限的。这是另外一个: Rebol以及诸如Orca,Red等的派生类。 >> 1 / 6->== 0.166666666666667
Izkata 2012年

Lua做到了。它只有一个Number类型,通常与C的double相同。
马查多2012年

在Clojure 1/6中,实际上是1/6(小数类型),被强制Double为1.66666 ...
kaoD 2012年

Answers:


17

大家都忘了帕斯卡吗?

1/6产量0.1666666...(支持任何精度)。

1 div 6 产量 0

C规则是否错误是有争议的。几乎所有C的算术运算符(其操作数为相同类型)都会产生相同类型的结果。为了保持一致性,有话要说。

此外,由于C主要针对系统级代码,因此大多数C程序根本不使用浮点数。一次,不小心将浮点代码添加到原本不需要的程序中可能是一个严重的问题。对于小型嵌入式系统来说,情况仍然可能如此,这也是C的主要目标。

在大多数C程序中,无论如何,截断整数除法可能就是您想要的。

如果1 / 6在C中产生浮点结果,则:

  • 这将是语言上的不一致。
  • 该标准将不得不作出的一个任意选择其中的浮点类型使用的结果(double可能看起来像自然的选择,但你可能会喜欢的额外的精度long double
  • 该语言仍然必须具有整数除法运算;执行浮点加法然后截断可能还不够好。

C 可以为两种除法提供单独的运算符,但是上面的第二点仍然适用:三种浮点类型中的哪一种将用于结果?而且由于可以很容易地在需要时进行浮点除法(对一个或两个操作数使用浮点常量,或者将一个或两个操作数都转换为浮点类型),因此显然不是'认为很重要。

在1974年的C手册版本(即K&R第一版出版的前四年)中,Ritchie甚至没有提到可能的混淆:

二进制/运算符表示除法。与乘法相同的类型注意事项适用

表示如果两个操作数均为int或类型char,则结果为类型int

是的,这对于某些C程序员,尤其是初学者来说,是一个混乱的根源-但是,由于C对新手非常友好,因此并未引起人们的注意。


5
帕斯卡。在C弄错之前弄清楚细节。™
Mason Wheeler 2012年

然后,Algol对其继任者进行了改进(C和Pascal都支持后者)。
AProgrammer

帕斯卡(Pascal)-使细节正确(给予或取10倍)
马丁·贝克特

1
我最初写过1.666666...,这显然是错误的。我la脚的借口是我写的Pascal测试程序印制了1.6666666666666667E-0001
Keith Thompson

16

实际上,此行为在Python 3中已更改,并且现在的行为确实与您期望的一样(//现在用于整数除法)。


谢谢。您还想使用其他任何编程语言吗?基本家庭也许?
2012年

1
@Pouya:这种行为是Pascal家族的标准行为。/总是产生浮点值,并且单独的运算符(div)用于整数除法。
梅森惠勒2012年

13

JavaScript出自著名语言。1.0 / 6.0 = 1/6 = 0.16666666666666666。

我认为这并不奇怪。根据经验,如果一种语言区分整数和浮点数字类型,则将两个整数相除将产生一个截断的整数,而不是浮点数。如果不是这样,很可能它将默认为浮点运算。这应该是程序员的预期行为。

请记住,这里还有其他一些功能,例如已经提到的单独的整数除法运算符或隐式类型转换。


6
这不是“经验法则”。这是C的规则,并且少数语言盲目地复制了C的错误。
梅森惠勒2012年

4
@MasonWheeler:FORTRAN是否“盲目复制C的错误”?我个人认为,设计良好的语言应使用单独的运算符来进行整数的截断除法和近似除法(对于值和参照相等性也要使用btw),但是在FORTRAN时代,设计决策可能是合理的。这并不意味着每种语言都应该像1950年代FORTRAN那样做。
2012年

3
低级语言需要进行这些区分。没有它们,高级/动态语言通常会更好。这是设计的权衡。我很欣赏JS中只有一个大笨拙的Number构造函数/类型,但是我想我会在尝试编写没有更严格的类型控制的高性能3D引擎时感到JS缺少。JS可能与其他语言有重叠的实用程序,但是我认为没有人会认为它是编写高性能,接近于Chrome的东西的首选。
埃里克·雷彭

2
编程之外的数学将仅整数规则视为除法规则。
埃里克·雷彭

5
@MasonWheeler:编程不是纯粹的数学。在数学上,1/6是有理数,不能用二进制浮点数精确表示。唯一精确的表示形式是分母的六倍于分子的比率。
凯文·克莱恩

7

许多语言的((1/6)*6)结果都是1,而不是0。例如PL / SQL,许多BASIC方言Lua。

偶然地,在所有这些语言中,1/6都会产生.166666667或0.16666666666667或类似的结果。我选择了((1/6)* 6)== 1变体以消除这些小的差异。


7
那不是问题。
RocMartí'12

20
偶然地,在所有这些语言中,1/6都会产生.166666667或0.16666666666667或类似的结果。我选择了((1/6)*6)==1变体来消除那些小的差异,但似乎我高估了某些人的数学技能。
user281377 2012年

1
@RocMartí是的,的确是……
MattDavey 2012年

1
我会惊讶地发现(1.0 / 6.0)* 6等于1!(1.0 / 6.0)的结果四舍五入将导致很小的差异。(尽管会有一些语言默认无穷精度)
Sjoerd 2012年

1
@Sjoerd:实际上,并不太令人惊讶。以小数形式考虑1/11 * 11的情况,所有值都精确到五个有效数字。1/11的值是9.0909 * 10 ^ -2。乘以11,则在四舍五入前将得到99.9999 * 10 / -2。四舍五入到五个有效数字,结果将是1.0000 * 10 ^ 0。请注意,关键是1/6的尾数为“ ... 0101010101 ...”。如果表示的最后一位是“ 1”,则将其乘以6并四舍五入将得出1。如果最后一位为零,则不会。
2012年

3

Haskell将1/6和1.0 / 6.0视为0.16666666666666666。它还将1 / 6.0和1.0 / 6设为相同的值。

这是由于Haskell中的基本数字类型与其他语言不太相同。真整数除法有些...复杂。


2

是的,Perl做到了。一线

perl -e '$x=1/6;print "$x\n";'

结果为:

0.166666666666667

我相信PHP的工作方式相同。

编辑添加:我还认为,所1/6 == 1.0/6.0讨论语言的弱类型是必要的(但不充分)条件。


为什么要弱打字(无论这意味着什么)?在两个参数均为整数的情况下,只需定义/即可(也)意味着浮点除法。

1
@delnan - en.wikipedia.org/wiki/Weak_typing我想这也许可以有一个强类型语言中,/这取决于类型的参数自动重载,但这似乎是违反原则最小惊讶的对我...

2
弱/强类型的输入是不确定的(正如Wiki所暗示的那样),请避免使用它并加以具体说明。我认为您的定义禁止隐式转换,但不是临时多态性?如果是这样,请考虑Haskell,它没有隐式转换,但是执行得很好(例如,99%的时间都可以工作,并且可以被凡人理解)数值多态性。为何这会令人惊讶?如果我必须在任意运算符的每个实例中添加多个点,这对我来说将是令人惊讶的(更不用说烦人了),具体取决于我希望的精确度。

2
@JackManey我认为对于大多数新手来说,1/2等于0比将两个整数除以双精度值更令人惊讶。毕竟,所有的整数也不是在数学除法下关闭的。同样正如delnan所指出的,Haskell是强类型语言的一个示例,其中两个整数上的/不产生整数。Python 3是另一个。
sepp2k 2012年

1
Haxe语言是强类型的(尽管可以推断),但是它没有整数除法,只有浮点数。所以你去了。
K.Steff

2

在Squeak Smalltalk /上,对整数创建Fraction对象。因此,尽管这与float除法不同,但仍(1/6)*6返回1。


在所有Smalltalk-80衍生物中(即几乎所有Smalltalks)。琥珀色是当代的例外之一(可以理解,已被编译为JavaScript)。
herby 2012年



2

MATLAB。默认情况下,数字文字为双精度。

>> 1/6
ans =
    0.1667

2

默认情况下,Clojure确实使用分数。它与1.0 / 6.0不同,但是您可以在需要时使用float或转换为1.0 / 6.0 double

user=> (/ 1 6)
1/6
user=> (* (/ 1 6) 2)
1/3
user=> (pos? (/ 1 6)) ; Is 1/6 > 0?
true
user=> (float (/ 1 6))
0.16666667

1

令人惊讶的是,它似乎在Windows PowerShell (版本3)中正常运行。

PS C:\> 1.0 / 6.0
0.166666666666667

PS C:\> 1/6
0.166666666666667

正如提到的sepp2k一样,它似乎也可以在Python 3中工作。我在REPL上可以轻松使用的另外两种语言,Scala和Ruby,都进行整数除法并产生0。


0

Rexx语言始终会产生算术上正确的答案。例如:5/2 = 2.5。Rexx是一种很棒的语言,尚未得到充分利用。从理论上讲,当编译器无法确定您想要什么时,最好执行正确的数学运算,但是,这可能没有效率。Rexx还提供//运算符。

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.