为什么python除法结果会有小数点0_关于python:为什么整数除法会在许多脚本语言中向下取整?...
在我測試過的語言中,- (x div y )不等于-x div y; 我已經在Python中測試了//,在Ruby中測試了/,在Perl 6中測試了div; C具有類似的行為。
該行為通常是按照規范進行的,因為div通常被定義為除法結果的四舍五入,但是從算術的角度來看,這沒有多大意義,因為它使div在 取決于符號的不同方式,這會引起混亂,例如有關如何在Python中完成操作的帖子。
該設計決策背后是否有一些特定的理論依據,還是只是從頭開始定義div? 顯然,Guido van Rossum在博客文章中使用了一個一致性參數,該參數解釋了Python的完成方式,但是如果選擇四舍五入,您也可以具有一致性。
(受PMurias在#perl6 IRC頻道中提出的問題的啟發)
在Python中,FWIW 被稱為地板分割。 試試這個:.7 .1。 請注意,它不會計算為int。
FWIW,在Python中,您可以使用雙重否定來獲得上限劃分:例如-(-23 10)
理想情況下,我們希望每個b>0都有兩個操作div和mod滿足:
(a div b) * b + (a mod b) = a
0 <= (a mod b) < b
(-a) div b = -(a div b)
但是,這在數學上是不可能的。如果以上所有條件都成立,我們將有
1
21 div 2 = 0
1 mod 2 = 1
因為這是(1)和(2)的唯一整數解。因此,到(3),
10 = -0 = -(1 div 2) = (-1) div 2
由(1)表示
1-1 = ((-1) div 2) * 2 + ((-1) mod 2) = 0 * 2 + ((-1) mod 2) = (-1) mod 2
制作與(2)相矛盾的(-1) mod 2 < 0。
因此,我們需要放棄(1),(2)和(3)中的某些屬性。
一些編程語言放棄(3),而將div舍入(Python,Ruby)。
在某些(很少)情況下,該語言提供了多個除法運算符。例如,在Haskell中,與Python類似,div,mod僅滿足(1)和(2),并且quot,rem僅滿足(1)和(3)。后一對運算符將除法舍入為零,以返回負余數為代價,例如,我們有(-1) `quot` 2 = 0和(-1) `rem` 2 = (-1)。
C#也放棄(2),并允許%返回負的余數。連貫地,整數除法向零舍入。從C99開始的Java,Scala,Pascal和C也采用了這種策略。
C#放棄了(2)。 C#中的%運算符不是" mod"運算符。它是"余數"運算符,余數可以為負。
@EricLippert:出于好奇:如果是這種情況,為什么操作員ID字符串為op_Modulus而不是op_Remainder?
@Heinzi:我沒有確定的充分理由。這只是很長的小錯誤列表中的一個,這些小錯誤并不重要。
只需將方程式的兩邊都除以零!
浮點運算是由IEEE754定義的,并考慮了數字應用程序,默認情況下,以非常嚴格定義的方式舍入到最接近的可表示值。
通用國際標準未定義計算機中的整數運算。語言(尤其是C家族的語言)授予的操作傾向于遵循基礎計算機提供的任何內容。某些語言比某些語言更健壯地定義某些操作,但是為了避免在當時可用(和流行)的計算機上實現過于困難或緩慢的實現,它們會選擇一種非常接近其行為的定義。
因此,整數運算傾向于在溢出時回繞(用于加法,乘法和左移),并且在產生不精確的結果時(用于除法和右移)會向負無窮大舍入。在二進制補碼二進制算術中,這兩個都是在整數各自的結尾處的簡單截斷;處理極端情況的最簡單方法。
其他答案則討論了語言與除法運算可能提供的余數或模運算符之間的關系。不幸的是,他們倒退了。余數取決于除法的定義,而不是相反的定義,而模數可以獨立于除法定義-如果兩個參數碰巧都是正數且除法向下取整,則它們的結果相同,因此人們很少注意到。
大多數現代語言都提供余數運算符或模數運算符,很少會同時提供。庫函數可以為關心差異的人們提供其他操作,即余數保留除數的符號,而模數保留除數的符號。
這是一個有趣的觀點,也因為您是指模塊化算術。如果問題是:"為什么整數除法會在許多腳本語言中取整?",您是否認為相同的答案可能適用?
@iGian好吧,事實是,由于我在答案中概述的原因,大多數語言都無法進行整數除法。通常,他們要么調用CPU DIV指令并只接受它的功能,要么調用實現歐幾里得除法的子例程,并且通常執行相同的操作。一個合理的問題可能是"為什么在大多數其他語言都沒有的情況下,語言X會四舍五入(或趨近于零,或趨近于零)?" -但您必須指定X,答案將特定于該語言。
那么,許多腳本語言會舍入整數除法,因為CPU DIV基本上是歐幾里得除法的實現? ----我很好奇為什么需要四舍五入。您能推薦一種語言X嗎?
@iGian就是這樣,我不知道一個副手-您是提出它的人。除非另有明確說明,否則有幾種方法會默默地將整數操作數強制轉換為浮點并執行浮點除法。例如。 BBC BASIC將定義為FP div,將DIV定義為帶舍入的整數。 6502甚至沒有DIV指令,因此帶有子程序。
在C和C ++和Java中,除法向零截斷,向右移向負無窮大。
如何處理負無窮大是處理極端情況的最簡單方法?為什么不趨向于零或正無窮大或下一個整數?
@ GOTO0我的答案就在那:二進制截斷補碼算術。具有除法指令的現代CPU通常會這樣做,許多軟件子例程也會這樣做。但是,在子例程中實現它的一種方法是對操作數的正形式執行無符號除法,然后再固定符號。將趨近于零。
事實并非如此:整數除法根本不涉及截斷(在所有中間步驟中僅計算整數值)。同樣,在x86和類似體系結構上,整數除法指令始終四舍五入為零。
@ GOTO0:"向零"舍入模式的名稱是"截斷"。例如浮點trunc()函數:en.cppreference.com/w/c/numeric/math/trunc。如果將整數除法視為產生實數的數學除法,然后將其四舍五入為整數,則舍入舍入模式將表示該行為。當然,那不是其在內部實際實施的方式。 BTW,對于算術右移,向-Inf顯然是2s補碼中最簡單的:您只需移入符號位的副本即可得到。
但是這個答案有一個錯誤。在大多數語言/ ISA中,似乎聲稱整數除法通常會向-Inf取整。那對于所有具有除法指令的現代CPU體系結構都是不正確的,對于ISO C99和ISO C ++ 11也是不正確的,它們都精確地指定了有符號整數除法舍入語義(以匹配所有現代CPU的功能)。在C ++中使用負數進行整數除法舍入。先前的修訂版將其留給實現來選擇一種行為(以提高使用不同語義的硬件的效率)。
@PeterCordes:實際上,"截斷"僅描述符號幅度表示(例如IEEE-754浮點)中的舍入為零。在二進制補碼表示法中,截斷實際上是朝著負無窮大舍入,這就是從最有意義的一端轉移符號位副本的簡單權宜之計。特別是,如果0xFFFF為-1,則0xFFFE為-2。
@Chromatix:啊,我明白了這個術語的意義。但是我的意思是數學截斷(en.wikipedia.org/wiki/Truncation),即截斷是指將小數點(或二進制)點后的某些位置截斷,或者將小數部分去除/歸零。截斷是數學中的一個術語,不僅僅是計算機科學/工程學,其含義是向零舍入。我認為,不管實現如何,都將舍入為零是最有意義的。 (即使這意味著您不能簡單地截斷2s補碼表示的位。)
Wikipedia在這方面有很棒的文章,包括歷史和理論。
只要語言滿足(a/b) * b + (a%b) == a的歐幾里得除法屬性,則地板除法和截斷除法都是連貫且在算術上有意義的。
當然,人們喜歡爭辯說,一個顯然是正確的,而另一個顯然是錯誤的,但它比起明智的討論更具有圣戰的性質,并且通常更多地與選擇他們的早期首選語言有關。其他。他們通常也傾向于主要為他們選擇的%爭論,盡管先選擇/然后選擇匹配的%可能更有意義。
地板(如Python):
就像唐納德·克努斯(Donald Knuth)所建議的那樣。
%跟隨除數的符號顯然是大約70%的學生猜測
通常將運算符讀取為mod或modulo而不是remainder。
" C做到了" —甚至都不是事實。1
截斷(如C ++):
使整數除法與IEEE浮點除法更加一致(在默認的四舍五入模式下)。
更多的CPU實現了它。 (在歷史的不同時期可能并非如此。)
運算符被讀取為modulo而不是remainder(即使這實際上與他們的觀點背道而馳)。
從概念上講,除法屬性更多地是關于余數而不是模量。
運算符被讀取為mod而不是modulo,因此應遵循Fortran的區分。 (這聽起來很愚蠢,但可能是C99的關鍵所在。請參閱此線程。)
"歐幾里得"(如Pascal- /底數或根據符號截斷,因此%永遠不會為負):
尼克勞斯·沃思(Niklaus Wirth)認為,沒有人對肯定的mod感到驚訝。
雷蒙德·布特(Raymond T. Boute)后來提出,您不能憑借其他任何一條規則天真地實現歐幾里得除法。
多種語言都提供。通常,與Ada,Modula-2,一些Lisps,Haskell和Julia一樣,它們使用與mod有關的名稱(對于Python風格的運算符)和與rem有關的名稱對于C ++風格的運算符。但并非總是如此-例如,Fortran調用相同的內容modulo和mod(如上面C99所述)。
我們不知道為什么Python,Tcl,Perl和其他有影響力的腳本語言大多選擇地板。正如問題中提到的,Guido van Rossum的答案僅說明了為什么他必須選擇三個一致的答案之一,而不是為什么他選擇了自己選擇的答案。
但是,我懷疑C的影響是關鍵。大多數腳本語言(至少在最初是用C語言實現的),并從C語言借用其操作員清單。C89的實現定義的%顯然已損壞,不適合Tcl或Python之類的"友好"語言。 C將運算符稱為" mod"。因此它們采用模數,而不是余數。
1。盡管問題說了什么(很多人都使用它作為參數),但C的行為實際上與Python和其朋友并不相似。 C99需要截斷分割,而不是分割。 C89允許使用任一版本,也允許使用任一版本的mod,因此無法保證除法屬性,也無法編寫具有符號整數除法的可移植代碼。真是壞了。 sub>
一些Lisps:Common Lisp定義了mod和rem,請參見lispworks.com/documentation/HyperSpec/Body/f_mod_r.htm和lispworks.com/documentation/HyperSpec/Body/f_floorc.htm
@coredump和其他一些Lisps使用其他名稱。 MacLisp只提供了一個,而Racket今天也做同樣的事情。 Scheme提供了三個(modulo,remainder,和Wirth樣式的mod)。我認為答案不需要與世界上每種語言的方言相關聯;說"某些Lips"使用mod / rem樣式命名似乎足夠了。
因為整數除法的含義是完整答案包括余數。
...而根據定義,其余部分必須始終為正?顯然,并非每種語言都適用:在C99中,其余符號與紅利符號相同
是的,這是正確的,評論的下限使我發瘋!
@jjmerelo在Python中,其余部分(使用%或divmod())始終與除數具有相同的符號。例如123 % -10-> -7
@ SeanFrancisN.Ballais顯然只是個慣例問題。維基百科關于模運算的條目說:當a或n為負數時,天真定義會失效,并且編程語言會在定義這些值的方式上有所不同。
正如寶拉(Paula)所說,這是由于剩余的原因。
該算法基于歐幾里得除法。
在Ruby中,您可以編寫以下代碼來重建一致性:
1
2puts (10/3)*3 + 10%3
#=> 10
它在現實生活中的作用相同。 10個蘋果和3個人。好的,您可以將蘋果切成三等分,但要超出設定的整數。
使用負數時,也保持一致性:
1
2
3puts (-10/3)*3 + -10%3 #=> -10
puts (10/(-3))*(-3) + 10%(-3) #=> 10
puts (-10/(-3))*(-3) + -10%(-3) #=> -10
商總是向下取整(沿負軸向下),并且提示如下:
1
2
3
4
5
6
7
8puts (-10/3) #=> -4
puts -10%3 #=> 2
puts (10/(-3)) #=> -4
puts 10%(-3) # => -2
puts (-10/(-3)) #=> 3
puts -10%(-3) #=> -1
因此,除法和模運算必須是連貫的,這很清楚。但是,您可以選擇向上或向下取整,只要這些等式成立,就可以保持連貫性。
@jjmerelo,我同意你的看法,在數學上,您可以選擇其他規則,其中# 10 3 = 4 # 10 % 3 = -2 # 3 * 4 - 2 = 10。但這不適用于-2不存在的自然數集。
@iGian您缺少的答案是,有多種方法可以保持負數的一致性而不更改正數的結果。
總結
以上是生活随笔為你收集整理的为什么python除法结果会有小数点0_关于python:为什么整数除法会在许多脚本语言中向下取整?...的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: php 如何配置 redis,php 如
- 下一篇: java实验1机动车实验目的_《Java