Modulo-bewerking met negatieve getallen

In een C-programma probeerde ik de onderstaande bewerkingen (alleen om het gedrag te controleren)

x = 5 % (-3);
 y = (-5) % (3);
 z = (-5) % (-3); 
printf("%d ,%d ,%d", x, y, z); 

Het gaf me uitvoer als (2, -2 , -2)in gcc. Ik verwachtte elke keer een positief resultaat. Kan een modulus negatief zijn? Kan iemand dit gedrag verklaren?


Antwoord 1, autoriteit 100%

C99 vereistdat wanneer a/brepresentatief is:

(a/b) * b+a%bis gelijk aan a

Dit is logisch, logisch.Toch?

Laten we eens kijken waar dit toe leidt:


Voorbeeld A. 5/(-3)is -1

=> (-1) * (-3)+5%(-3)= 5

Dit kan alleen gebeuren als 5%(-3)2 is.


Voorbeeld B. (-5)/3is -1

=> (-1) * 3+(-5)%3= -5

Dit kan alleen gebeuren als (-5)%3-2

is


Antwoord 2, autoriteit 91%

De operator %in C is niet de operator modulomaar de operator rest.

Modulo- en restoperatoren verschillen met betrekking tot negatieve waarden.

Bij een rest-operator is het teken van het resultaat hetzelfde als het teken van het deeltal (teller) terwijl bij een modulo-operator het teken van het resultaat hetzelfde is als de deler (noemer).

C definieert de bewerking %voor a % bals:

 a == (a / b * b) + a % b

met /de gehele deling met truncatie richting 0. Dat is de truncatie die wordt gedaan naar 0(en niet naar negatieve oneindigheid) die de %definieert als een restoperator in plaats van een modulo-operator.


Antwoord 3, autoriteit 40%

Gebaseerd op de C99-specificatie: a == (a / b) * b + a % b

We kunnen een functie schrijven om (a % b) == a - (a / b) * bte berekenen!

int remainder(int a, int b)
{
    return a - (a / b) * b;
}

Voor modulo-bewerking kunnen we de volgende functie hebben (uitgaande van b > 0)

int mod(int a, int b)
{
    int r = a % b;
    return r < 0 ? r + b : r;
}

Mijn conclusie is dat a % bin C een restbewerking is en GEEN modulobewerking.


Antwoord 4, autoriteit 37%

Ik denk niet dat het nodig is om te controleren of het getal negatief is.

Een eenvoudige functie om de positieve modulo te vinden zou deze zijn –

Bewerken:Ervan uitgaande dat N > 0en N + N - 1 <= INT_MAX

int modulo(int x,int N){
    return (x % N + N) %N;
}

Dit werkt voor zowel positieve als negatievewaarden van x.

Originele PS:ook zoals aangegeven door @chux, als je x en N iets als respectievelijk INT_MAX-1 en INT_MAX kunnen bereiken, vervang dan gewoon intdoor long long int.

En als ze ook limieten van lange lengte overschrijden (d.w.z. in de buurt van LLONG_MAX), dan moet u positieve en negatieve gevallen afzonderlijk behandelen, zoals beschreven in andere antwoorden hier.


Antwoord 5, autoriteit 5%

De andere antwoorden hebben uitgelegd in C99of later, deling van gehele getallen met negatieve operanden afkappen naar nul.

Houd er rekening mee dat in C89of het resultaat naar boven of naar beneden wordt afgerond, door de implementatie wordt bepaald. Omdat (a/b) * b + a%bgelijk is aan ain alle standaarden, is het resultaat van %met negatieve operanden ook implementatie- gedefinieerd in C89.


Antwoord 6, autoriteit 4%

Kan een modulus negatief zijn?

%kan negatief zijn omdat het de rest-operatoris, de rest na deling, niet na Euclidische_divisie. Sinds C99 kan het resultaat 0, negatief of positief zijn.

// a % b
 7 %  3 -->  1  
 7 % -3 -->  1  
-7 %  3 --> -1  
-7 % -3 --> -1  

De gezochte moduloOP is een klassieke Euclidische modulo, niet %.

Ik verwachtte elke keer een positief resultaat.

Om een Euclidische modulo uit te voeren die goed gedefinieerd is wanneer a/bwordt gedefinieerd, a,bvan enig teken zijn en het resultaat nooit negatief is:

int modulo_Euclidean(int a, int b) {
  int m = a % b;
  if (m < 0) {
    // m += (b < 0) ? -b : b; // avoid this form: it is UB when b == INT_MIN
    m = (b < 0) ? m - b : m + b;
  }
  return m;
}
modulo_Euclidean( 7,  3) -->  1  
modulo_Euclidean( 7, -3) -->  1  
modulo_Euclidean(-7,  3) -->  2  
modulo_Euclidean(-7, -3) -->  2   

Antwoord 7

Volgens de C99-standaard, sectie 6.5.5
Multiplicatieve operatoren
, het volgende is vereist:

(a / b) * b + a % b = a

Conclusie

Het teken van het resultaat van een restbewerking, volgens
tot C99, is hetzelfde als dat van het dividend.

Laten we enkele voorbeelden bekijken (dividend / divisor):

Als alleen dividend negatief is

(-3 / 2) * 2  +  -3 % 2 = -3
(-3 / 2) * 2 = -2
(-3 % 2) must be -1

Als alleen deler negatief is

(3 / -2) * -2  +  3 % -2 = 3
(3 / -2) * -2 = 2
(3 % -2) must be 1

Als zowel deler als dividend negatief zijn

(-3 / -2) * -2  +  -3 % -2 = -3
(-3 / -2) * -2 = -2
(-3 % -2) must be -1

6.5.5 Multiplicatieve operatoren

Syntaxis

  1. multiplicatieve-expressie:
    • cast-expression
    • multiplicative-expression * cast-expression
    • multiplicative-expression / cast-expression
    • multiplicative-expression % cast-expression

Beperkingen

  1. Elk van de operanden moet een rekenkundig type hebben. De
    operanden van de operator %hebben het type integer.

Semantiek

  1. De gebruikelijke rekenkundige conversies worden uitgevoerd op de
    operanden.

  2. Het resultaat van de binaire operator *is het product van
    de operanden.

  3. Het resultaat van de operator /is het quotiënt van
    de deling van de eerste operand door de tweede; de
    resultaat van de operator %is de rest. In beide
    bewerkingen, als de waarde van de tweede operand nul is,
    het gedrag is niet gedefinieerd.

  4. Als gehele getallen worden gedeeld, het resultaat van de /operator
    is het algebraïsche quotiënt met elk fractioneel deel
    weggegooid [1]. Als het quotiënt a/brepresenteerbaar is,
    de uitdrukking (a/b)*b + a%bzal gelijk zijn aan a.

[1]: Dit wordt vaak “afknotting naar nul” genoemd.


Antwoord 8

Het resultaat van de Modulo-bewerking hangt af van het teken van de teller, en dus krijg je -2 voor yen z

Hier is de referentie

http://www.chemie.fu- berlin.de/chemnet/use/info/libc/libc_14.html

Integer-divisie

Deze sectie beschrijft functies voor het uitvoeren van deling van gehele getallen.
Deze functies zijn overbodig in de GNU C-bibliotheek, aangezien in GNU C de
‘/’ operator rondt altijd af naar nul. Maar in andere C
implementaties, kan ‘/’ anders afronden met negatieve argumenten.
div en ldiv zijn handig omdat ze specificeren hoe de
quotiënt: richting nul. De rest heeft hetzelfde teken als de
teller.


Antwoord 9

In de wiskunde, waar deze conventies vandaan komen, is er geen bewering dat modulo-rekenkunde een positief resultaat zou moeten opleveren.

Bijv.

1 mod 5 = 1, maar het kan ook gelijk zijn aan -4. Dat wil zeggen, 1/5 levert een rest op van 1 van 0 of -4 van 5. (Beide factoren van 5)

Ook,
-1 mod 5 = -1, maar het kan ook gelijk zijn aan 4. Dat wil zeggen, -1/5 levert een rest -1 op van 0 of 4 van -5. (Beide factoren van 5)

Kijk voor meer informatie in equivalentieklassenin wiskunde.


Antwoord 10

Modulus-operator geeft de rest.
Modulus-operator in c neemt meestal het teken van de teller

  1. x = 5 % (-3) – hier is de teller positief en dus resulteert in 2
  2. y = (-5) % (3) – hier is de teller negatief, vandaar dat het resulteert in -2
  3. z = (-5) % (-3) – hier is de teller negatief, vandaar dat het resulteert in -2

Ook de operator modulus(rest) kan alleen worden gebruikt met een geheel getal en kan niet worden gebruikt met drijvende komma.


Antwoord 11

Ik geloof dat het nuttiger is om te denken aan modzoals het is gedefinieerd in abstracte rekenkunde; niet als een operatie, maar als een geheel andere rekenklasse, met verschillende elementen en verschillende operatoren. Dat betekent dat optelling in mod 3niet hetzelfde is als de “normale” optelling; dat is; integer optellen.

Dus als je dat doet:

5 % -3

Je probeert de integer5 toe te wijzen aan een element in de set van mod -3. Dit zijn de elementen van mod -3:

{ 0, -2, -1 }

Dus:

0 => 0, 1 => -2, 2 => -1, 3 => 0, 4 => -2, 5 => -1

Stel dat je om de een of andere reden 30 uur op moet blijven, hoeveel uur heb je dan nog over van die dag? 30 mod -24.

Maar wat C implementeert is niet mod, het is een restant. Hoe dan ook, het punt is dat het zinvol is om negatieven terug te sturen.


Antwoord 12

Het lijkt erop dat het probleem is dat /niet verdiepingis.

int mod(int m, float n)
{  
  return m - floor(m/n)*n;
}

Other episodes