eine gerade oder ungerade Zahl unterscheiden
-
cooky451 schrieb:
ipsec schrieb:
Das optimiert der Compiler schon. Der Modulooperator ist hier verständlicher.
Tut er nicht. MSVC:
if (isEven(i)) 012216CA mov ecx,dword ptr [esp+4] 012216CE and ecx,80000001h 012216D4 jns main+2Bh (12216DBh) 012216D6 dec ecx 012216D7 or ecx,0FFFFFFFEh 012216DA inc ecx 012216DB jne main+3Ch (12216ECh)
VS
if (isEven(i)) 003516CA mov cl,byte ptr [esp+4] 003516CE not cl 003516D0 test cl,1 003516D3 je main+34h (3516E4h)
Hat mich auch überrascht. Ich frage mich, ob irgendeine Regel im Standard verhindert, dass hier optimiert werden darf.
Was kommt denn raus, wenn Du den Test nochmal mit unsigned int machst und als den Zielprozessor was modernes einstellst?
-
volkard schrieb:
Was kommt denn raus, wenn Du den Test nochmal mit unsigned int machst und als den Zielprozessor was modernes einstellst?
Gut erkannt, mit unsigned geht es. [Edit: Das könnte bedeuten, dass AND nicht so definiert ist, dass es als Lösung immer genügt. Wobei das für übliche Systeme wohl egal sein dürfte.]
http://en.wikipedia.org/wiki/Signed_number_representations#Comparison_table
Interessant, dass es bei negativen ungeraden Zahlen auch die Möglichkeit gibt, ein 0 bit am Ende zu haben. Die Frage ist, wie weit der Standard hier definiert. Soweit ich mich erinnern kann, lässt er es offen, was tatsächlich bedeuten würde, dass die !(i & 1)-Methode nicht immer funktionieren muss.
-
Das ist, damit er bei -1 % 2 == -1 haben kann. Ich versteh nur nicht, was das soll. Das Verhalten für negative Operanden schreibt der Standard nicht vor, er lässt es offen. Es ist außerdem unpraktisch und nicht mit dem Gebrauch von Modulo in der Mathematik konform.
-
Bashar schrieb:
Das ist, damit er bei -1 % 2 == -1 haben kann. Ich versteh nur nicht, was das soll. Das Verhalten für negative Operanden schreibt der Standard nicht vor, er lässt es offen. Es ist außerdem unpraktisch und nicht mit dem Gebrauch von Modulo in der Mathematik konform.
Aber wegen -1/2=0 will man es wieder, sagte irgend jemand mir irgendwann irgendwo.
Damit man aus a/b und a%b wieder a basteln kann. a=(a/b)*b + (a%b).
-
Bashar schrieb:
Das ist, damit er bei -1 % 2 == -1 haben kann. Ich versteh nur nicht, was das soll. Das Verhalten für negative Operanden schreibt der Standard nicht vor, er lässt es offen. Es ist außerdem unpraktisch und nicht mit dem Gebrauch von Modulo in der Mathematik konform.
Im neuen Standard besteht keine Wahl mehr.
n3290 schrieb:
5.6/4 The binary / operator yields the quotient, and the binary % operator yields the remainder from the division of the first expression by the second. If the second operand of / or % is zero the behavior is undefined. For integral operands the / operator yields the algebraic quotient with any fractional part discarded;81 if the quotient a/b is representable in the type of the result, (a/b)*b + a%b is equal to a.
-
camper schrieb:
Bashar schrieb:
Das ist, damit er bei -1 % 2 == -1 haben kann. Ich versteh nur nicht, was das soll. Das Verhalten für negative Operanden schreibt der Standard nicht vor, er lässt es offen. Es ist außerdem unpraktisch und nicht mit dem Gebrauch von Modulo in der Mathematik konform.
Im neuen Standard besteht keine Wahl mehr.
n3290 schrieb:
5.6/4 The binary / operator yields the quotient, and the binary % operator yields the remainder from the division of the first expression by the second. If the second operand of / or % is zero the behavior is undefined. For integral operands the / operator yields the algebraic quotient with any fractional part discarded;81 if the quotient a/b is representable in the type of the result, (a/b)*b + a%b is equal to a.
Die Wahl wäre, daß gegen -inf gerundet wird und nicht gegen 0, wenn Zahlen dividiert werden.
Also -7/2=-4. Oder?
-
volkard schrieb:
camper schrieb:
Bashar schrieb:
Das ist, damit er bei -1 % 2 == -1 haben kann. Ich versteh nur nicht, was das soll. Das Verhalten für negative Operanden schreibt der Standard nicht vor, er lässt es offen. Es ist außerdem unpraktisch und nicht mit dem Gebrauch von Modulo in der Mathematik konform.
Im neuen Standard besteht keine Wahl mehr.
n3290 schrieb:
5.6/4 The binary / operator yields the quotient, and the binary % operator yields the remainder from the division of the first expression by the second. If the second operand of / or % is zero the behavior is undefined. For integral operands the / operator yields the algebraic quotient with any fractional part discarded;81 if the quotient a/b is representable in the type of the result, (a/b)*b + a%b is equal to a.
Die Wahl wäre, daß gegen -inf gerundet wird und nicht gegen 0, wenn negative Zahlen dividiert werden.
Also -7/2=-4. Oder?Genau. Das ist jetzt nicht mehr konform.
-
Und dabei haste den Part sogar noch hervorgehoben. Sorry.
-
Oh, das ist schon in C99 so und wurde wohl nachgezogen. Man sollte dann aber IMHO nicht mehr von "Modulo-Operator" sprechen, das ist jetzt der "Rest-Operator".
Hier gibts eine schöne Tabelle, in welchen Programmiersprachen es Modulo- und Rest-Operatoren gibt:
http://en.wikipedia.org/wiki/Modulo_operationDie meisten, die beides haben, nennen den einen mod und den anderen rem. Unser % ist rem.
-
Interessant wäre noch, ob Compiler hinreichend intelligent sind, um
int x = ...; int y = ( x % 2 + 2 ) % 2;
zu optimieren.
-
camper schrieb:
Interessant wäre noch, ob Compiler hinreichend intelligent sind, um
int x = ...; int y = ( x % 2 + 2 ) % 2;
zu optimieren.
Hoffentlich hab ich alles richtig entziffert.
movl $_ZSt3cin, %edi //&cin laden nach edi leaq 12(%rsp), %rsi //&x laden nach rsi call _ZNSirsERi //op<< aufrufen movl 12(%rsp), %esi //y=x //also erstmal in ein register tun movl $_ZSt4cout, %edi //&cout laden nach edi andl $1, %esi //y = ( y % 2 + 2 ) % 2; //optimiert call _ZNSolsEi //op>> aufrufen
Da guckstu. Wiedermal der magische gcc.
-
Die Frage ist bei solchen Sachen immer (zumindest für mich), ob da einer aus Langeweile ein spezielles Pattern implementiert hat oder ob das ein allgemeiner Mechanismus ist.
-
Du kannst dich ja in den GCC-Sourcen auf die Suche machen.
-
Bashar schrieb:
Die Frage ist bei solchen Sachen immer (zumindest für mich), ob da einer aus Langeweile ein spezielles Pattern implementiert hat oder ob das ein allgemeiner Mechanismus ist.
Da alles konstant ist, kriegt der Compiler das locker mit den allgemeinen Regeln hin. Was für ein spezielles Pattern soll das denn sein?
-
nurf schrieb:
Da alles konstant ist, kriegt der Compiler das locker mit den allgemeinen Regeln hin.
x ist nicht konstant. Und so locker kann das nicht sein, der MSVC kann das z.B. nicht.
-
Ist leider tatsächlich nur eine spezielle Behandlung für gewisse Zahlen.
cin >> x; int y = ( x % 1000 + 1000 ) % 1000; cout << y << '\n'; int z = (unsigned)x % 1000; cout << z << '\n';
führt zu
call _ZNSirsERi movl 8(%rsp), %esi movl $_ZSt4cout, %edi movl %esi, %eax imull %ebx // (1) movl %esi, %eax sarl $31, %eax sarl $6, %edx subl %eax, %edx imull $1000, %edx, %edx subl %edx, %esi addl $1000, %esi movl %esi, %eax imull %ebx // (2) movl %esi, %eax sarl $31, %eax sarl $6, %edx subl %eax, %edx imull $1000, %edx, %edx subl %edx, %esi call _ZNSolsEi movq %rbp, %rsi movl $1, %edx movq %rax, %rdi movb $10, 15(%rsp) call _ZSt16__ostream_insertIcSt11char_traitsIcEERSt13basic_ostreamIT_T0_ES6_PKS3_l movl 8(%rsp), %esi movl $_ZSt4cout, %edi movl %esi, %eax mull %ebx shrl $6, %edx imull $1000, %edx, %edx subl %edx, %esi call _ZNSolsEi movq %rbp, %rsi movl $1, %edx movq %rax, %rdi movb $10, 15(%rsp) call _ZSt16__ostream_insertIcSt11char_traitsIcEERSt13basic_ostreamIT_T0_ES6_PKS3_l
also 2 Divisionen (durch Multiplikation ersetzt) im ersten Fall.