web-dev-qa-db-de.com

Gleichzeitig teilen und Rest erhalten?

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?

42
Ben

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.

46
bta

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;
}
30
Eloff

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.

10
Stringer
3
Pedro Rodrigues

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 

MSDN-Referenz

3
BrunoLM

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.)

2
LukeH

FWIW, Haskell hat sowohl divMod als auch quotRem , wobei letztere direkt der Maschinenanweisung entspricht (gemäß Integraloperatoren quot vs. div ), divMod jedoch nicht.

1
Jon Wolski

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));

Javadoc: https://docs.Oracle.com/javase/7/docs/api/Java/math/BigDecimal.html#divideAndRemainder(Java.math.BigDecimal)

0
Iván
    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
    }
0
Ernesto Alfonso

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
    }
0
Ernesto Alfonso