[Python3] "A // B" und "math.floor (A / B)" sind nicht immer gleich! ??

Hinweis

** Dieser Artikel enthält die Geschichte von "Atcoder Beginner Contest 148 E - Double Factorial". Bitte stöbern Sie nicht, wenn Sie dieses Problem selbst lösen möchten. ** **.

Überblick

Ich bin beim Lösen von Atcoder auf ein Titelproblem gestoßen, daher werde ich diesen Artikel als Erinnerung veröffentlichen und die Meinungen von Python-Experten hören.

Problem

Atcoder Beginner Contest 148 E - Double Factorial

Definieren Sie für eine ganze Zahl n größer oder gleich 0 f (n) wie folgt:

・ F.(n) = 1 [n <Wann]\\
・ F.(n) = nf(n-2) [n \Wenn geq 2]

Angesichts der ganzen Zahl N. Finden Sie heraus, wie viele Nullen folgen, wenn f (N) dezimal geschrieben wird.

Umgebung

Phänomen

In den folgenden beiden Codes ist ** der obere Teil AC (richtige Antwort) **, der untere Teil WA (falsche Antwort) **.

AC.py


import math
N = int(input())
ans = 0
if N % 2 != 0:
    pass
else:
    for i in range(0, 25):
        ans += N // (10 * 5 ** i)
print(ans)

WA.py


import math
N = int(input())
ans = 0
if N % 2 != 0:
    pass
else:
    for i in range(0, 25):
        ans += math.floor(N / (10 * 5 ** i))
print(ans)

Es gibt 15 Testfälle für dieses Problem, aber die folgenden 2 Testfälle wurden zu WA.

[15.txt]
IN:  237590337949089028
OUT: 29698792243636116

[16.txt]
IN:  999003990299500294
OUT: 124875498787437525

Erwartete Ursache

** Die wahrscheinliche Ursache ist eine Schreibweise dessen, was ich auf verschiedene Weise versucht habe, bis ich die Ursache identifiziert habe. ** **. ** Ich möchte nur das Ergebnis wissen! Ich hoffe, Sie können mit dem nächsten Kapitel fortfahren. ** **.

Die folgenden Teile beziehen sich auf AC und WA.

ans += N // (10 * 5 ** i) #AC
ans += math.floor(N / (10 * 5 ** i)) #WA

Beide machen ähnliche Dinge und werden wahrscheinlich das gleiche Ergebnis liefern, aber nicht.

Lassen Sie uns vorerst ausgeben, wo der Fehler auftritt. Gehen Sie wie folgt vor.

debug.py


import math
N = int(input())
ans_ac = 0
ans_wa = 0
if N % 2 != 0:
    pass
else:
    for i in range(0, 25):
        ans_ac = N // (10 * 5 ** i)
        ans_wa = math.floor(N / (10 * 5 ** i))
        print('i =', i)
        print('d =', N / (10 * 5 ** i))
        print('AC:', ans_ac)
        print('WA:', ans_wa)

Das Ergebnis ist wie folgt.

i = 0 #Error: 2
d = 2.3759033794908904e+16
AC:  23759033794908902
WA:  23759033794908904

i = 1 #Error: 1
d = 4751806758981781.0
AC: 4751806758981780
WA: 4751806758981781

i = 2 #Error: 0
d = 950361351796356.1
AC: 950361351796356
WA: 950361351796356

i = 3 #Error: 0
d = 190072270359271.22
AC: 190072270359271
WA: 190072270359271

(Unten weggelassen)

Nachfolgende Wiederholungen (i ist 3 oder mehr und weniger als 25) hatten alle 0 AC- und WA-Fehler (AC und WA sind gleich). Es scheint, dass nur zu Beginn der Iteration ein Fehler aufgetreten ist (i = 0, 1). Im Moment scheine ich nichts so zu wissen, wie es ist, also habe ich beschlossen, über etwas anderes nachzudenken.

Hier kam mir eines in den Sinn. Welche Arten dieser Berechnungen gibt es? In Python gibt es zwei Typen, die reelle Zahlen darstellen.

Ersteres hat keine Genauigkeitsgrenzen, letzteres jedoch. Welche Art von Verschiebung haben die beiden fraglichen Berechnungsmethoden?

abc.001.jpeg

In Bezug auf "//" gemäß dem offiziellen Dokument

x // y Der Quotient aus x und y wird abgerundet Auch als Integer Division bekannt. Der Ergebnistyp ist nicht unbedingt ein Ganzzahltyp, aber der Ergebniswert ist eine Ganzzahl. Das Ergebnis wird immer auf negative Unendlichkeit gerundet.

Es gibt. Bei der AC-Berechnung scheint es, dass sie einer Variablen zugewiesen wird, ohne auch nur einmal ein Float-Typ zu werden.

Aber was ist mit WA-Berechnungen? Dies durchläuft den Float-Typ einmal in Abhängigkeit vom Berechnungsergebnis von "x / y". Ich habe es in der Umgebung überprüft.

test.py


A = 4
B = 2
print(type(A), type(B))
print(type(A / B))
print(A / B)

'''
<class 'int'> <class 'int'>
<class 'float'>
2.0
'''

Mit anderen Worten, es ist bereits ein Float-Typ, bevor math.floor () verwendet wird. Ist // und math.floor () nicht ähnlich und verschieden? Ich dachte, aber es scheint nicht die Ursache zu sein.

Die Definition von "math.floor ()" in Official Documents lautet wie folgt.

Gibt die "Etage" von x zurück (die größte Ganzzahl kleiner oder gleich x). Wenn x keine Gleitkommazahl ist, wird x .__ floor __ () intern ausgeführt und ein integrierter Wert zurückgegeben.

Vielmehr erwartete ich, dass die WA-Berechnung über ** float type ** erfolgte und zunächst einen unangemessenen Wert an math.floor () übergab.

Wie zum Zeitpunkt der Typeinführung erwähnt, weist der Float-Typ im Gegensatz zum int-Typ eine Genauigkeitsbeschränkung auf. Es gab folgende Möglichkeiten, dies zu überprüfen.

dig.py


import sys
print(sys.float_info.dig)
# 15

Das offizielle Dokument lautet wie folgt.

sys.float_info Benannte Taples mit Informationen zu Float-Typen dig: Maximale Dezimalstelle, die im Gleitkomma genau angezeigt werden kann

Anscheinend kann der Float-Typ bis zu 15 Stellen genau sein, aber die darüber hinausgehenden Stellen sind verdächtig ... Lassen Sie uns nun den Testfall erneut bestätigen, der die WA früher ausgestellt hat. Dieses Mal konzentrieren wir uns auf die Anzahl der Ziffern.

i = 0 #Error: 2
d = 2.3759033794908904e+16 #17 Ziffern,Minderheit 0 Ziffern
AC:  23759033794908902     # 23759033794908904
WA:  23759033794908904     #17 Ziffern>15 Ziffern

i = 1 #Error: 1
d = 4751806758981781.0     #16 Ziffern,Minderheit 1 Ziffer
AC: 4751806758981780       #16 Ziffern>15 Ziffern
WA: 4751806758981781

i = 2 #Error: 0
d = 950361351796356.1      #15 Ziffern,Minderheit 1 Ziffer
AC: 950361351796356        #15 Ziffern=15 Ziffern
WA: 950361351796356

i = 3 #Error: 0
d = 190072270359271.22     #15 Ziffern,2 Ziffern
AC: 190072270359271        #15 Ziffern=15 Ziffern
WA: 190072270359271

(Unten weggelassen)

Der ganzzahlige Ziffernteil ist diesmal wichtig für die Antwort auf das Atcoder-Problem. Es stellt sich heraus, dass ein Fehler auftritt, wenn die ganzzahligen Ziffern die Float-Genauigkeit von 15 Ziffern überschreiten! Wenn "4 <= i <25", wird die ganzzahlige Ziffer nie größer als 15 Ziffern, so dass anscheinend kein Fehler aufgetreten ist.

Es schien, dass AC diesmal nicht war, indem der Float-Typ "d" mit dem Fehler in "math.floor ()" gebissen wurde.

Zusammenfassung

--A // B undmath.floor (A / B)machen dasselbe

Das ist es. Danke fürs Lesen!

Recommended Posts

[Python3] "A // B" und "math.floor (A / B)" sind nicht immer gleich! ??
Python a + = b und a = a + b sind unterschiedlich
Python open und io.open sind gleich
Python-Memo- "wenn nicht A und B" war "wenn (nicht A) und B"
a () und a .__ call__ () sind nicht gleichwertig
[Python] gibt A [oder / und] B zurück
ffmpeg-Erstellen Sie eine Python-Umgebung und teilen Sie das Video
Berücksichtigung der Stärken und Schwächen von Python
Python3> rund (a - b, 7)
Das von Python berechnete VIF und das von Excel berechnete VIF sind unterschiedlich.
Gleitkommazahlen entsprechen nicht der Minderheit der Dezimalzahlen
Eine Lösung für das Problem, dass Dateien mit [und] nicht in glob.glob () aufgeführt sind
Das verallgemeinerte lineare Modell (GLM) und das neuronale Netz sind gleich (1)
Stellen Sie sicher, dass alle Elemente in der Liste in Python identisch sind
Anders als der Importtyp von Python. Bedeutung von aus A Import B.
Erstellen Sie den Code, der in Python "A und vorgeben B" ausgibt
Unter CentOS (RHEL) 8 können keine Python- und Pip-Befehle verwendet werden
Das verallgemeinerte lineare Modell (GLM) und das neuronale Netz sind gleich (2)
Der Websocket von toio (nodejs) und python / websocket stellen keine Verbindung her.
Ich habe versucht, den Unterschied zwischen A + = B und A = A + B in Python herauszufinden
Neue Python-Grammatik und Funktionen, die im Einführungsbuch nicht erwähnt werden
Pythons regulärer Ausdruck, str und unicode sind nüchtern
Überprüfung der Theorie, dass "Python und Swift ziemlich ähnlich sind"
[Einführung in Python] Verwendung des Booleschen Operators (und ・ oder ・ nicht)
So zeigen Sie Bytes in Java und Python auf die gleiche Weise an
Die Geschichte von Python und die Geschichte von NaN
ABC127 A, B, C Erklärung (Python)
[Python] Was sind @classmethod und Dekorateure?
[Python] Machen Sie die Funktion zu einer Lambda-Funktion
ABC128 A, B, C Kommentar (Python)
ABC126 A, B, C Erklärung (Python)
[Einführung in Python] Was ist der Unterschied zwischen einer Liste und einem Taple?
[AtCoder Erklärung] Kontrollieren Sie ABC184 A, B, C Probleme mit Python!
Ich dachte, es sei dasselbe wie Python, und ich war süchtig nach dem Problem, dass der Ruby-Interpreter nicht gestartet wurde.
Löse ABC175 A, B, C mit Python
Module und Pakete in Python sind "Namespaces"
Schreiben Sie den Test in die Python-Dokumentzeichenfolge
Durchsuche das Labyrinth mit dem Python A * -Algorithmus
Verbinde viel Python oder und und
Python> Schlüsselwortargumente> hoge (** {'a': 1, 'b': 2, 'c': 3})
Führen Sie den Python-Interpreter im Skript aus
[Python] Generieren einer Sequenz, die dieselben Elemente berücksichtigt
[Python] [Meta] Ist der Python-Typ ein Typ?
Python> Python enthält nicht den letzten Offset
Löse ABC165 A, B, D mit Python
Eine Geschichte über Python Pop und Append
Academia Potter und der mysteriöse Python-Pass
Die Geschichte der Verarbeitung A von Blackjack (Python)
[Python] Ein Fortschrittsbalken auf dem Terminal
[Python] Ein Programm, das die Partitur rundet
Testen Sie das Hochladen von Bildern, indem Sie in Python erstellen, ohne Dummy-Bilddateien in Django zu platzieren
Machen Sie aus einem Python-Programm einen Daemon und führen Sie es automatisch aus, wenn das Betriebssystem gestartet wird
[Erklärung zum AtCoder] Kontrollieren Sie die A-, B-, (C), D-Probleme von ABC165 mit Python!
[AtCoder-Erklärung] Kontrollieren Sie die A-, B-, C- und D-Probleme von ABC183 mit Python!
Python - Lesen Sie Daten aus einer numerischen Datendatei und suchen Sie die multiple Regressionslinie.
Python-Skript, das SQL-Dateien liest, BigQuery ausführt und CSV speichert
Erstellen wir ein einfaches Empfangssystem mit dem serverlosen Python-Framework Chalice und Twilio
Verwenden Sie libsixel, um Sixel in Python auszugeben und das Matplotlib-Diagramm an das Terminal auszugeben.