1/6'nın 1.0 / 6.0 ile aynı şekilde davrandığı bir programlama dili var mı?


11

Birkaç gün önce C ++ 'da programlama yaparken, bu hatayı yaptım (bunu yapma geçmişim var!). Kodumun bir bölümünde 1/6 vardı ve 0.16666666666 olmasını bekliyordum ki durum böyle değil. Hepinizin bildiği gibi sonuç 0 - C, C ++, Java, Python, hepsi aynı şekilde davranıyor.

Facebook sayfamda yayınlıyorum ve şimdi 1/6aynı şekilde davranan bir programlama dili olup olmadığı konusunda tartışma var 1.0/6.0.


5
Haskell. 1/6 = 0.16666666666666666
t123

PowerShell, 1'i bir tam sayı olduğu için beni şaşırtan 0.166666666666667 üretir. Beklediğiniz değeri üreten başka bazı .NET dilleri var.
JohnL

Teorik olarak, sınırsız sayıda var. İşte bir tane daha: Rebol , Orca, Red ve benzeri türevler. >> 1 / 6->== 0.166666666666667
Izkata

Lua bunu yapar. Yalnızca tek bir Sayı türü vardır, bu genellikle C'nin çiftiyle aynıdır.
Machado

Clojure 1/6aslında 1/6 (kesirli tip), zorlanan Double, 1.66666 ...
kaoD

Yanıtlar:


17

Herkes Pascal'ı unuttu mu?

1/6verim 0.1666666...(herhangi bir hassasiyet desteklenir).

1 div 6 verim 0

C kuralının bir hata olup olmadığı tartışılabilir. İşlenenlerin aynı tipte olduğu C'nin aritmetik operatörlerinin neredeyse tamamı aynı tipte bir sonuç verir. Tutarlılık için söylenecek bir şey var.

Ayrıca, C öncelikle sistem seviyesi kodunu hedeflediğinden, çoğu C programı kayan nokta kullanmaz. Bir kerede, yanlışlıkla ihtiyaç duymayan bir programa yanlışlıkla kayan nokta kodu eklemek ciddi bir sorun olabilir. Muhtemelen hala, C için büyük bir hedef olan küçük gömülü sistemler için durum böyledir.

Çoğu C programında, tamsayı bölümünün kısaltılması muhtemelen sadece istediğiniz şeydir.

1 / 6C'de bir kayan nokta sonucu verildiyse , o zaman:

  • Dilde bir tutarsızlık olurdu.
  • Standart , sonuç için hangi kayan nokta türünün kullanılacağını keyfi bir seçim yapmak zorunda kalacaktır ( doubledoğal seçim gibi görünebilir, ancak ekstra hassasiyetini tercih edebilirsiniz long double)
  • Dil ediyorum hala tamsayı bölümü için bir ameliyat geçirmek zorunda; kayan nokta eklemesi yapmak ve daha sonra kırpmak yeterince iyi olmayacaktır.

C , iki tür bölüm için ayrı operatörler sağlayabilirdi , ancak yukarıdaki ikinci nokta yine de geçerli olurdu: sonuç için üç kayan nokta türünden hangisi kullanılır? İhtiyacınız varsa kayan nokta bölme elde etmek yeterince kolay olduğundan (işlenenlerden biri veya her ikisi için bir kayan nokta sabiti kullanın veya işlenenlerden birini veya her ikisini kayan nokta türüne dökün), görünüşe göre Bunu önemli saymadım.

C kılavuzunun 1974 versiyonunda (K&R'nin ilk baskısının yayınlanmasından 4 yıl önce), Ritchie olası karışıklıktan bile bahsetmiyor:

İkili / operatör bölümü gösterir. Çarpma işlemiyle aynı tür hususlar geçerlidir

ki her iki işlenen de türse intveya charsonucun tür olduğunu söyler int.

Evet, bazı C programcıları, özellikle yeni başlayanlar için bir karışıklık kaynağı - ancak C'nin acemi dostu olduğu not edilmedi.


5
Pascal. C'nin yanlış
Mason Wheeler

Ve sonra Algol halefleri üzerinde bir gelişme oldu (hem C hem de Pascal'ın sayısında).
AProgrammer

Pascal - ayrıntıları doğru yapmak (10 faktörü vermek veya almak)
Martin Beckett

1
Aslında yazdım 1.666666..., bu kesinlikle yanlış. Topal mazeretim, yazdığım Pascal test programının basılması1.6666666666666667E-0001
Keith Thompson

16

Aslında bu davranış Python 3'te değiştirildi ve şimdi beklediğiniz gibi davranıyor ( //şimdi tamsayı bölümü için kullanılıyor).


Teşekkürler. Aklınızda başka programlama dilleri var mı? Temel aile belki?
Pouya

1
@Pouya: Bu davranış Pascal ailesi için standarttır. /her zaman bir kayan nokta değeri üretir ve divtamsayı bölümü için ayrı bir operatör ( ) kullanılır.
Mason Wheeler

13

Belirgin diller dışında JavaScript. 1.0 / 6.0 = 1/6 = 0.16666666666666666.

Bunu şaşırtıcı olarak görmüyorum. Başparmak kuralı olarak, bir dil tamsayı ve kayan nokta sayısal türleri arasında ayrım yaparsa, iki tamsayıyı bölmek kayan nokta yerine kesilmiş bir tamsayı verir. Değilse, büyük olasılıkla kayan nokta işlemlerini varsayılan olarak yapar. Bu, programcı tarafında beklenen davranış olmalıdır.

Burada daha önce bahsedilen ayrı tamsayı bölme operatörü veya örtük tipte döküm gibi burada da olabilecek ek şeyler olduğunu unutmayın.


6
Bu "temel kural" değildir. Bu bir C kuralı ve C'nin hatalarını körü körüne kopyalayan birkaç dil.
Mason Wheeler

4
@MasonWheeler: FORTRAN "C'nin hatasını körü körüne kopyaladı mı?" Ben şahsen iyi tasarlanmış dillerin kesilmiş bölüm için tam sayıların yaklaşık bölünmesine (ve ayrıca btw, değer ve referans eşitliği için) ayrı işleçler kullanması gerektiğine inanıyorum, ancak FORTRAN günlerindeki tasarım kararı muhtemelen makul. Bu, her dilin FORTRAN'ın 1950'lerde yaptığı gibi yapması gerektiği anlamına gelmez.
supercat

3
Daha düşük seviyeli diller bu ayrımları yapmalıdır. Daha yüksek seviye / dinamik diller onlarsız daha iyidir. Bu bir tasarım değiş tokuşu. JS'de sadece bir büyük aptal Numara yapıcısına / tipine sahip olduğumu takdir ediyorum, ancak daha katı tip kontrolü olmadan yüksek performanslı bir 3D motor yazmaya çalışırken JS'nin eksik olduğunu hissettiğimi hayal ediyorum. JS'nin diğer dillerle örtüşen bir yardımcı programı olabilir, ancak hiç kimsenin bunu yüksek performanslı krom türüne yakın şeyler yazmak için bir goto olarak düşüneceğini sanmıyorum.
Erik Reppen

2
Programlama dışındaki matematik bölüm için sadece tamsayı kurallarını dikkate alır.
Erik Reppen

5
@MasonWheeler: Programlama saf matematik değildir. Matematiksel olarak, 1/6 rasyonel bir sayıdır ve ikili kayan noktalı sayı ile tam olarak temsil edilemez. Tek kesin temsil payda ile payın altı katıdır.
kevin cline

7

((1/6)*6)1 ile sonuçlanan birçok dil vardır . 0 ile değil. Örneğin, PL / SQL, birçok BASIC lehçesi, Lua.

Yanlışlıkla, tüm bu dillerde 1/6, .166666667 veya 0.16666666666667 veya benzer bir şeyle sonuçlanır. Bu küçük farklılıklardan kurtulmak için ((1/6) * 6) == 1 varyantını seçtim.


7
Soru bu değil.
Roc Martí

20
Yanlışlıkla, tüm bu dillerde 1/6, .166666667 veya 0.16666666666667 veya benzer bir şeyle sonuçlanır. ((1/6)*6)==1Bu küçük farklılıklardan kurtulmak için varyantı seçtim , ancak bazı insanların matematik becerilerini abarttığım gibi görünüyor.
user281377 8

1
@ RocMartí evet, gerçekten ...
MattDavey

1
(1.0 / 6.0) * 6'nın 1'e tam olarak eşit olduğunu görmek beni şaşırttı! (1.0 / 6.0) sonucunun yuvarlanması küçük bir fark yaratacaktır. (Sonsuz hassasiyeti varsayılan olarak ayarlayan birkaç dil olmasına rağmen)
Sjoerd

1
@Sjoerd: Aslında bunun tam olarak fazla olması fazla değil. 1/11 * 11 senaryosunu ondalık sayıyla, tüm değerleri beş anlamlı rakama doğru olarak düşünün. 1/11 değeri 9.0909 * 10 ^ -2'dir. 11 ile çarptığınızda, yuvarlamadan önce 99.9999 * 10 / -2 elde edilir. Beş önemli rakama yuvarlayın ve sonuç 1.0000 * 10 ^ 0 olacaktır. Anahtarın 1/6 mantisinin "... 0101010101 ..." olduğunu unutmayın. Bir gösterimin son biti "1" ise, bunu altı ile çarpmak ve yuvarlama 1 değerini verir. Son bit sıfır olsaydı, olmazdı.
supercat

3

Haskell 1/6 ve 1.0 / 6.0'a aynı şekilde 0.16666666666666666 olarak davranır. Aynı zamanda 1 / 6.0 ve 1.0 / 6'yı da aynı değer olarak gösterir.

Bunun nedeni, Haskell'deki temel sayısal türlerin diğer dillerle tamamen aynı olmamasıdır. Gerçek tamsayı bölümü biraz ... karmaşıktır.


2

Evet, Perl biliyor. Tek astar

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

sonuçları:

0.166666666666667

PHP'nin aynı şekilde çalıştığına inanıyorum.

Eklemek için düzenlendi: Ayrıca 1/6 == 1.0/6.0, söz konusu dilin zayıf yazılması için gerekli (ancak yeterli olmayan) bir koşulun olduğuna inanıyorum .


Heck neden zayıf yazım (ne anlama geliyorsa) gerekli olur? Her iki argümanın da tamsayı olması durumunda, yalnızca şamandıra bölünmesini tanımlayın / da (ayrıca) ortalama olarak tanımlayın.

1
@delnan - en.wikipedia.org/wiki/Weak_typing Sanırım /argümanların türlerine bağlı olarak otomatik olarak aşırı yüklenmiş, ancak en az şaşkınlık ilkesinin ihlali gibi görünen güçlü bir şekilde yazılmış bir dile sahip olmak mümkün olabilir . me ...

2
Zayıf / güçlü yazım kötü tanımlanmıştır (wiki'nin de ima ettiği gibi), lütfen kaçının ve spesifik olun. Ben senin tanımını örtük dönüşüm yasaklar, ama geçici polimorfizm değil mi? Öyleyse, örtük dönüşümü olmayan ancak oldukça iyi yürütülen (zamanın% 99'unda çalışır ve ölümlüler tarafından anlaşılabilir) sayısal polimorfizmi olan Haskell'i düşünün. Ve bu neden şaşırtıcı olurdu? İstediğim kesinliğe bağlı olarak, herhangi bir operatörün her bir örneğine bir dizi nokta eklemek zorunda kalsaydım çok daha şaşırtıcı olurdu (sinir bozucu dememek).

2
@JackManey Bence en yeni gelenler için 1/2 tamsayı 0'a eşit olması çok daha şaşırtıcı olduğunu düşünüyorum iki tamsayı bölmek bir çift sonuç verir. Sonra tüm tamsayılar matematik bölümü altında kapalı değil. Ayrıca delnan'ın işaret ettiği gibi, Haskell, iki tamsayı üzerinde / üzerinde bir tamsayı oluşturmayan, güçlü bir şekilde yazılmış bir dile örnektir. Ve Python 3 başka bir şey.
sepp2k

1
Haxe dili güçlü (çıkartılarak da olsa) yazılmıştır ve yine de tamsayı bölümü yoktur, sadece yüzer. Al işte ozaman, buyur.
K.Steff

2

Squeak Smalltalk'ta /tamsayılar Kesir nesneleri oluşturur. Yani bu şamandıra bölümü ile aynı olmasa da, yine de (1/6)*61 döndürür.


Tüm Smalltalk-80 türevlerinde (yani neredeyse tüm Smalltalks). Amber, çağdaş istisnalardan biridir (anlaşılabilir, JavaScript'e derlenmiştir).
herby



2

MATLAB. Sayısal değişmez değerler varsayılan olarak iki katına çıkar.

>> 1/6
ans =
    0.1667

2

Clojure varsayılan olarak kesirler kullanır. 1.0 / 6.0 ile aynı değildir, ancak ihtiyacınız olduğunda floatveya doubleihtiyacınız olduğunda dönüştürebilirsiniz .

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

Şaşırtıcı bir şekilde, Windows PowerShell'de (sürüm 3) düzgün çalışıyor gibi görünüyor .

PS C:\> 1.0 / 6.0
0.166666666666667

PS C:\> 1/6
0.166666666666667

Ayrıca sepp2k de belirtildiği gibi Python 3'te çalışıyor gibi görünüyor. REPL, Scala ve Ruby'de hazır bulunduğum diğer iki dil de tamsayı bölme yapıyor ve 0 verimi sağlıyor.


0

Rexx dili her zaman aritmetik olarak doğru bir cevap üretir. Örneğin: 5/2 = 2.5. Rexx yeterince kullanılmamış harika bir dildir. Teorik olarak, bir derleyici ne istediğinizi belirleyemediğinde, doğru matematiği yapmak daha iyidir, ancak bu etkili olmayabilir. Rexx ayrıca // operatörünü de sağlar.

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.