Anscheinend hat x86 (und wahrscheinlich viele andere Befehlssätze) sowohl den Quotienten als auch den Rest einer Divisionsoperation in separate Register gestellt.
Jetzt können wir Compilern wahrscheinlich vertrauen, dass sie einen Code wie diesen so optimieren, dass er nur einen Aufruf zum Teilen verwendet:
( x / 6 )
( x % 6 )
Und wahrscheinlich auch. Unterstützen trotzdem languages (oder Bibliotheken, die hauptsächlich nach Sprachen suchen) die gleichzeitige Ausgabe von Divide- und Modulo-Ergebnissen? Wenn ja, wie lauten sie und wie sieht die Syntax aus?
C hat div
UND ldiv
. Ob diese separate Anweisungen für den Quotienten und den Rest erzeugen, hängt von Ihrer speziellen Implementierung der Standardbibliothek und den Compiler- und Optimierungseinstellungen ab. Ab C99 haben Sie auch lldiv
für größere Zahlen.
Python tut.
>>> divmod(9, 4)
(2, 1)
Was seltsam ist, weil Python eine Hochsprache ist.
Ruby auch:
11.divmod(3) #=> [3, 2]
* EDIT *
Es ist zu beachten, dass der Zweck dieser Operatoren wahrscheinlich ist, die Arbeit nicht so effizient wie möglich zu erledigen. Es ist wahrscheinlicher, dass die Funktionen aus Gründen der Korrektheit/Portabilität vorhanden sind.
Für Interessierte glaube ich das ist der Code der Python-Implementierung für Integer divmod:
static enum divmod_result
i_divmod(register long x, register long y,
long *p_xdivy, long *p_xmody)
{
long xdivy, xmody;
if (y == 0) {
PyErr_SetString(PyExc_ZeroDivisionError,
"integer division or modulo by zero");
return DIVMOD_ERROR;
}
/* (-sys.maxint-1)/-1 is the only overflow case. */
if (y == -1 && UNARY_NEG_WOULD_OVERFLOW(x))
return DIVMOD_OVERFLOW;
xdivy = x / y;
/* xdiv*y can overflow on platforms where x/y gives floor(x/y)
* for x and y with differing signs. (This is unusual
* behaviour, and C99 prohibits it, but it's allowed by C89;
* for an example of overflow, take x = LONG_MIN, y = 5 or x =
* LONG_MAX, y = -5.) However, x - xdivy*y is always
* representable as a long, since it lies strictly between
* -abs(y) and abs(y). We add casts to avoid intermediate
* overflow.
*/
xmody = (long)(x - (unsigned long)xdivy * y);
/* If the signs of x and y differ, and the remainder is non-0,
* C89 doesn't define whether xdivy is now the floor or the
* ceiling of the infinitely precise quotient. We want the floor,
* and we have it iff the remainder's sign matches y's.
*/
if (xmody && ((y ^ xmody) < 0) /* i.e. and signs differ */) {
xmody += y;
--xdivy;
assert(xmody && ((y ^ xmody) >= 0));
}
*p_xdivy = xdivy;
*p_xmody = xmody;
return DIVMOD_OK;
}
In C # /. NET haben Sie Math.DivRem
: http://msdn.Microsoft.com/en-us/library/system.math.divrem.aspx
Aber nach diesem Thread ist dies keine Optimierung.
Allgemeine LISP-Funktionen: http://www.lispworks.com/documentation/HyperSpec/Body/f_floorc.htm
Wie von Stringer Bell erwähnt, gibt es DivRem
, die nicht optimiert ist bis .NET 3.5.
Unter .NET 4.0 wird NGen verwendet.
Die Ergebnisse erhielt ich mit Math.DivRem
(debug; release = ~ 11000ms)
11863
11820
11881
11859
11854
Ergebnisse die ich mit MyDivRem
erhielt (debug; release = ~ 11000ms)
29177
29214
29472
29277
29196
Ziel für x86.
Math.DivRem
Verwendungsbeispiel
int mod1;
int div1 = Math.DivRem(4, 2, out mod1);
Methodensignaturen
DivRem(Int32, Int32, Int32&) : Int32
DivRem(Int64, Int64, Int64&) : Int64
.NET 4.0-Code
[TargetedPatchingOptOut("Performance critical to inline across NGen image boundaries")]
public static int DivRem(int a, int b, out int result)
{
result = a % b;
return (a / b);
}
.NET 4.0 IL
.custom instance void System.Runtime.TargetedPatchingOptOutAttribute::.ctor(string) = { string('Performance critical to inline across NGen image boundaries') }
.maxstack 8
L_0000: ldarg.2
L_0001: ldarg.0
L_0002: ldarg.1
L_0003: rem
L_0004: stind.i4
L_0005: ldarg.0
L_0006: ldarg.1
L_0007: div
L_0008: ret
Das .NET-Framework hat Math.DivRem
:
int mod, div = Math.DivRem(11, 3, out mod);
// mod = 2, div = 3
Obwohl DivRem
nur ein Wrapper ist, der ungefähr so aussieht:
int div = x / y;
int mod = x % y;
(Ich habe keine Ahnung, ob der Jitter so etwas in einer einzelnen Anweisung optimieren kann oder nicht.)
FWIW, Haskell hat sowohl divMod
als auch quotRem
, wobei letztere direkt der Maschinenanweisung entspricht (gemäß Integraloperatoren quot vs. div ), divMod
jedoch nicht.
In Java hat die Klasse BigDecimal
die Operation divideAndRemainder
, die ein Array von 2 Elementen mit dem Ergebnis und dem Rest der Division zurückgibt.
BigDecimal bDecimal = ...
BigDecimal[] result = bDecimal.divideAndRemainder(new BigDecimal(60));
int result,rest;
_asm
{
xor edx, edx // pone edx a cero; edx = 0
mov eax, result// eax = 2AF0
mov ecx, radix // ecx = 4
div ecx
mov val, eax
mov rest, edx
}
Dies gibt das Ergebnis als Rest zurück
int result,rest;
_asm
{
xor edx, edx // pone edx a cero; edx = 0
mov eax, result// eax = 2AF0
mov ecx, radix // ecx = 4
div ecx
mov val, eax
mov rest, edx
}