Java: Wie kann ich integer-division, die Runden in Richtung -Unendlich, anstatt 0?
(Hinweis: nicht das gleiche wie diese andere Frage seit der OP nie explizit angegeben Rundung in Richtung 0 oder -Unendlich)
JLS 15.17.2 sagt, dass die integer-division " rundet in Richtung null. Wenn ich will floor()
-wie Verhalten für positive Teiler (I don ' T care über das Verhalten für negative Teiler), was ist der einfachste Weg, dies zu erreichen, die numerisch richtige für alle Eingänge?
int ifloor(int n, int d)
{
/* returns q such that n = d*q + r where 0 <= r < d
* for all integer n, d where d > 0
*
* d = 0 should have the same behavior as `n/d`
*
* nice-to-have behaviors for d < 0:
* option (a). same as above:
* returns q such that n = d*q + r where 0 <= r < -d
* option (b). rounds towards +infinity:
* returns q such that n = d*q + r where d < r <= 0
*/
}
long lfloor(long n, long d)
{
/* same behavior as ifloor, except for long integers */
}
(update: ich möchte eine Lösung, die sowohl für int
und long
Arithmetik.)
- dies hat eine doppelte, aber ich kann es nicht finden, und wenn es nicht ein Duplikat ist, dann bin ich nur Total überrascht, dass es nicht kommen die noch nach 3+ Jahren von StackOverflow.
- In der
d < 0
Bedingungen für den Rest, ich glaube, du hast ein paar von inversen Zeichen. Es sieht aus wie Sie wollen0 <= r < -d
für option (a) undd < r <= 0
für option (b). - rechts: danke, ich habe meine, die positive version der divisor. (und es hätte Rundung in Richtung +unendlich)
Du musst angemeldet sein, um einen Kommentar abzugeben.
Wenn Sie können Bibliotheken von Drittanbietern verwenden, Guave hat diese:
IntMath.divide(int, int RoundingMode.ETAGE)
undLongMath.divide(int, int RoundingMode.ETAGE)
. (Disclosure: ich trage zu Guave.)Wenn Sie nicht möchten, verwenden Sie ein Drittanbieter-Bibliothek für diese, können Sie sehen immer noch an der Umsetzung.
Gibt es eine ziemlich nette Formel für das, dass funktioniert, wenn
n < 0
undd > 0
: nehmen Sie das bitweise Komplement von n, tun die division, und dann nehmen Sie das bitweise Komplement des Ergebnisses.Für den Rest, eine ähnliche Konstruktion funktioniert (kompatibel mit
ifloordiv
in dem Sinne, dass die üblichen invarianteifloordiv(n, d) * d + ifloormod(n, d) == n
zufrieden ist) was eine Folge immer im Bereich[0, d)
.Negativen Teiler, die Formeln sind nicht ganz so sauber. Hier sind erweiterte Versionen von
ifloordiv
undifloormod
Folgen, dass Ihr 'nice-to-have' - Verhalten option (b) für negative Teiler.Für
d < 0
gibt es eine unvermeidbare problem Fall, wennd == -1
undn
istInteger.MIN_VALUE
, da dann das mathematische Ergebnis überläuft der Typ. In diesem Fall, die obige Formel gibt den umschlossenen Ergebnis, ebenso wie die üblichen Java-Teilung macht. So weit ich bin mir bewusst,, dies ist die einzige Ecke Fall, wo wir schweigend bekommen "falschen" Ergebnisse.d < 0
, aber haben nicht die Zeit nehmen, um herauszufinden, was Sie alle sind. Vielleicht sollte ich das tun.(Ich Tue alles für
long
s da die Antwort fürint
s ist die gleiche, nur Ersatzint
für jedenlong
undInteger
für jedenLong
.)Konnte man nur
Math.Boden
eine double-division, Ergebnis, ansonsten...Original Antwort:
Optimierte Antwort:
(Der Vollständigkeit halber, mit einem
BigDecimal
mit einemROUND_FLOOR
Rundung-Modus ist auch eine option.)Neuer edit: Jetzt bin ich nur versucht, um zu sehen, wie weit optimiert werden können, zum Spaß. Mit Mark ' s Antwort die beste, die ich habe, so weit ist:
(Verwendet billiger Operationen als die obige, aber etwas länger bytecode (29 vs. 26)).
int
Variablen (von denen ich nicht sicher bin), ist es nicht für die Arbeitlong
Variablen, weil der Mangel an Präzision.(n<0) ^ (d<0)
mitn^d < 0
. Der compiler könnte tun, um diese Optimierung für Sie, aber ich bezweifle es.^
) nicht*
.n
ist-3
undd
ist2
diese Funktion Ausgänge-1
(falsch).