Ich war neugierig zu wissen, wie ich eine Zahl auf die nächste ganze Zahl runden kann. Zum Beispiel, wenn ich hätte:
int a = 59 / 4;
das wäre 14,75, wenn es im Gleitkomma berechnet würde; Wie kann ich das Ergebnis als 15 in "a" speichern?
Ich war neugierig zu wissen, wie ich eine Zahl auf die nächste ganze Zahl runden kann. Zum Beispiel, wenn ich hätte:
int a = 59 / 4;
das wäre 14,75, wenn es im Gleitkomma berechnet würde; Wie kann ich das Ergebnis als 15 in "a" speichern?
Antworten:
int a = 59.0f / 4.0f + 0.5f;
Dies funktioniert nur bei der Zuweisung zu einem int, da nach dem '.' Alles verworfen wird.
Bearbeiten: Diese Lösung funktioniert nur in den einfachsten Fällen. Eine robustere Lösung wäre:
unsigned int round_closest(unsigned int dividend, unsigned int divisor)
{
return (dividend + (divisor / 2)) / divisor;
}
Die Standardsprache für die Ganzzahlrundung lautet:
int a = (59 + (4 - 1)) / 4;
Sie addieren den Divisor minus eins zur Dividende.
int i = (x + (n / 2)) / n;
?
int
. Wenn der Divisor oder die Dividende jedoch negativ ist, wird eine falsche Antwort ausgegeben. Der Hinweis auf @caf funktioniert auch nicht.
c = (INT_MAX + (4 - 1)) / 4;
gibt c = -536870911
zu Integer - Überlauf durch ...
Ein Code, der für jedes Zeichen in Dividende und Divisor funktioniert:
int divRoundClosest(const int n, const int d)
{
return ((n < 0) ^ (d < 0)) ? ((n - d/2)/d) : ((n + d/2)/d);
}
Als Antwort auf einen Kommentar "Warum funktioniert das eigentlich?" Können wir dies auseinander brechen. Beachten Sie zunächst, dass n/d
dies der Quotient wäre, der jedoch gegen Null abgeschnitten und nicht gerundet wird. Sie erhalten ein gerundetes Ergebnis, wenn Sie dem Zähler vor dem Teilen die Hälfte des Nenners hinzufügen, jedoch nur, wenn Zähler und Nenner dasselbe Vorzeichen haben. Wenn sich die Vorzeichen unterscheiden, müssen Sie vor dem Teilen die Hälfte des Nenners abziehen. Alles zusammen:
(n < 0) is false (zero) if n is non-negative
(d < 0) is false (zero) if d is non-negative
((n < 0) ^ (d < 0)) is true if n and d have opposite signs
(n + d/2)/d is the rounded quotient when n and d have the same sign
(n - d/2)/d is the rounded quotient when n and d have opposite signs
Wenn Sie ein Makro bevorzugen:
#define DIV_ROUND_CLOSEST(n, d) ((((n) < 0) ^ ((d) < 0)) ? (((n) - (d)/2)/(d)) : (((n) + (d)/2)/(d)))
Das Linux-Kernel-Makro DIV_ROUND_CLOSEST funktioniert nicht für negative Teiler!
BEARBEITEN: Dies funktioniert ohne Überlauf:
int divRoundClosest( int A, int B )
{
if(A<0)
if(B<0)
return (A + (-B+1)/2) / B + 1;
else
return (A + ( B+1)/2) / B - 1;
else
if(B<0)
return (A - (-B+1)/2) / B - 1;
else
return (A - ( B+1)/2) / B + 1;
}
int
Werten nahe min / max int ist dies die bisher beste Lösung.
floor(n / d + 0.5)
, wobei n und d Floats sind.
Sie sollten stattdessen Folgendes verwenden:
int a = (59 - 1)/ 4 + 1;
Ich gehe davon aus, dass Sie wirklich versuchen, etwas allgemeineres zu tun:
int divide(x, y)
{
int a = (x -1)/y +1;
return a;
}
x + (y-1) kann überlaufen und zu einem falschen Ergebnis führen. während x - 1 nur unterläuft, wenn x = min_int ...
(Bearbeitet) Das Runden von Ganzzahlen mit Gleitkomma ist die einfachste Lösung für dieses Problem. Je nach Problemstellung ist dies jedoch möglich. Beispielsweise kann in eingebetteten Systemen die Gleitkomma-Lösung zu kostspielig sein.
Dies mit ganzzahliger Mathematik zu tun, erweist sich als schwierig und ein wenig unintuitiv. Die erste veröffentlichte Lösung funktionierte für das Problem, für das ich sie verwendet hatte, in Ordnung, aber nachdem ich die Ergebnisse über den Bereich von ganzen Zahlen charakterisiert hatte, stellte sich heraus, dass sie im Allgemeinen sehr schlecht war. Das Durchsehen mehrerer Bücher über Bit Twiddling und eingebettete Mathematik liefert nur wenige Ergebnisse. Ein paar Notizen. Erstens habe ich nur auf positive ganze Zahlen getestet, meine Arbeit beinhaltet keine negativen Zähler oder Nenner. Zweitens ist ein umfassender Test von 32-Bit-Ganzzahlen rechenintensiv. Daher habe ich mit 8-Bit-Ganzzahlen begonnen und dann sichergestellt, dass ich mit 16-Bit-Ganzzahlen ähnliche Ergebnisse erzielt habe.
Ich begann mit den 2 Lösungen, die ich zuvor vorgeschlagen hatte:
#define DIVIDE_WITH_ROUND(N, D) (((N) == 0) ? 0:(((N * 10)/D) + 5)/10)
#define DIVIDE_WITH_ROUND(N, D) (N == 0) ? 0:(N - D/2)/D + 1;
Mein Gedanke war, dass die erste Version mit großen Zahlen überlaufen würde und die zweite mit kleinen Zahlen überlaufen würde. Ich habe 2 Dinge nicht berücksichtigt. 1.) Das 2. Problem ist tatsächlich rekursiv, da Sie D / 2 richtig runden müssen, um die richtige Antwort zu erhalten. 2.) Im ersten Fall laufen Sie häufig über und dann unter, die beiden heben sich gegenseitig auf. Hier ist ein Fehlerdiagramm der beiden (falschen) Algorithmen:
Dieses Diagramm zeigt, dass der erste Algorithmus nur für kleine Nenner falsch ist (0 <d <10). Unerwartet handhabt es große Zähler tatsächlich besser als die 2. Version.
Hier ist eine Darstellung des 2. Algorithmus:
Wie erwartet schlägt es für kleine Zähler fehl, aber auch für mehr große Zähler als die 1. Version.
Dies ist eindeutig der bessere Ausgangspunkt für eine korrekte Version:
#define DIVIDE_WITH_ROUND(N, D) (((N) == 0) ? 0:(((N * 10)/D) + 5)/10)
Wenn Ihr Nenner> 10 ist, funktioniert dies korrekt.
Für D == 1 wird ein Sonderfall benötigt, geben Sie einfach N zurück. Für D == 2, = N / 2 + (N & 1) // wird ein Sonderfall benötigt.
D> = 3 hat auch Probleme, wenn N groß genug wird. Es stellt sich heraus, dass größere Nenner nur Probleme mit größeren Zählern haben. Für eine 8-Bit-Nummer mit Vorzeichen sind die Problempunkte
if (D == 3) && (N > 75))
else if ((D == 4) && (N > 100))
else if ((D == 5) && (N > 125))
else if ((D == 6) && (N > 150))
else if ((D == 7) && (N > 175))
else if ((D == 8) && (N > 200))
else if ((D == 9) && (N > 225))
else if ((D == 10) && (N > 250))
(D / N für diese zurückgeben)
Im Allgemeinen ist der Punkt, an dem ein bestimmter Zähler schlecht wird, irgendwo in der Nähe
N > (MAX_INT - 5) * D/10
Dies ist nicht genau, aber nah. Wenn Sie mit 16-Bit- oder größeren Zahlen arbeiten, beträgt der Fehler <1%, wenn Sie in diesen Fällen nur eine C-Division (Kürzung) durchführen.
Für 16-Bit-Nummern mit Vorzeichen wären die Tests
if ((D == 3) && (N >= 9829))
else if ((D == 4) && (N >= 13106))
else if ((D == 5) && (N >= 16382))
else if ((D == 6) && (N >= 19658))
else if ((D == 7) && (N >= 22935))
else if ((D == 8) && (N >= 26211))
else if ((D == 9) && (N >= 29487))
else if ((D == 10) && (N >= 32763))
Natürlich würde für vorzeichenlose Ganzzahlen MAX_INT durch MAX_UINT ersetzt. Ich bin sicher, dass es eine genaue Formel zur Bestimmung des größten N gibt, das für ein bestimmtes D und eine bestimmte Anzahl von Bits funktioniert, aber ich habe keine Zeit mehr, um an diesem Problem zu arbeiten ...
(Mir scheint dieses Diagramm im Moment zu fehlen, ich werde es später bearbeiten und hinzufügen.) Dies ist ein Diagramm der 8-Bit-Version mit den oben genannten Sonderfällen :! [8-Bit mit Sonderfällen für 3 signiert0 < N <= 10
Beachten Sie, dass für 8 Bit der Fehler 10% oder weniger für alle Fehler im Diagramm beträgt, 16 Bit <0,1%.
Wie geschrieben, führen Sie eine Ganzzahlarithmetik durch, bei der alle Dezimalergebnisse automatisch abgeschnitten werden. Um eine Gleitkomma-Arithmetik durchzuführen, ändern Sie entweder die Konstanten in Gleitkommawerte:
int a = round(59.0 / 4);
Oder wandeln Sie sie in einen float
oder einen anderen Gleitkommatyp um:
int a = round((float)59 / 4);
In beiden Fällen müssen Sie die endgültige Rundung mit der round()
Funktion im math.h
Header durchführen. #include <math.h>
Verwenden Sie daher unbedingt einen C99-kompatiblen Compiler.
float
(IEEE) begrenzt den nützlichen Bereich dieser Lösung auf abs (a / b) <16.777.216.
lround
.
Vom Linux-Kernel (GPLv2):
/*
* Divide positive or negative dividend by positive divisor and round
* to closest integer. Result is undefined for negative divisors and
* for negative dividends if the divisor variable type is unsigned.
*/
#define DIV_ROUND_CLOSEST(x, divisor)( \
{ \
typeof(x) __x = x; \
typeof(divisor) __d = divisor; \
(((typeof(x))-1) > 0 || \
((typeof(divisor))-1) > 0 || (__x) > 0) ? \
(((__x) + ((__d) / 2)) / (__d)) : \
(((__x) - ((__d) / 2)) / (__d)); \
} \
)
typeof()
Teil von C oder eine compilerspezifische Erweiterung?
#define CEIL(a, b) (((a) / (b)) + (((a) % (b)) > 0 ? 1 : 0))
Ein weiterer nützlicher MAKROS (MUSS HABEN):
#define MIN(a, b) (((a) < (b)) ? (a) : (b))
#define MAX(a, b) (((a) > (b)) ? (a) : (b))
#define ABS(a) (((a) < 0) ? -(a) : (a))
ROUND
, nichtCEIL
int a, b;
int c = a / b;
if(a % b) { c++; }
Wenn Sie prüfen, ob ein Rest vorhanden ist, können Sie den Quotienten der Ganzzahldivision manuell aufrunden.
ceil
Funktion, keine richtige Rundung
Hier ist meine Lösung. Ich mag es, weil ich es besser lesbar finde und weil es keine Verzweigung hat (weder wenn noch ternäre).
int32_t divide(int32_t a, int32_t b) {
int32_t resultIsNegative = ((a ^ b) & 0x80000000) >> 31;
int32_t sign = resultIsNegative*-2+1;
return (a + (b / 2 * sign)) / b;
}
Vollständiges Testprogramm, das das beabsichtigte Verhalten veranschaulicht:
#include <stdint.h>
#include <assert.h>
int32_t divide(int32_t a, int32_t b) {
int32_t resultIsNegative = ((a ^ b) & 0x80000000) >> 31;
int32_t sign = resultIsNegative*-2+1;
return (a + (b / 2 * sign)) / b;
}
int main() {
assert(divide(0, 3) == 0);
assert(divide(1, 3) == 0);
assert(divide(5, 3) == 2);
assert(divide(-1, 3) == 0);
assert(divide(-5, 3) == -2);
assert(divide(1, -3) == 0);
assert(divide(5, -3) == -2);
assert(divide(-1, -3) == 0);
assert(divide(-5, -3) == 2);
}
&
In ((a ^ b) & 0x80000000) >> 31;
ist redundant, da die niedrigen Bits sowieso nach der Verschiebung weggeworfen werden
// To do (numer/denom), rounded to the nearest whole integer, use:
#define ROUND_DIVIDE(numer, denom) (((numer) + (denom) / 2) / (denom))
Anwendungsbeispiel:
int num = ROUND_DIVIDE(13,7); // 13/7 = 1.857 --> rounds to 2, so num is 2
Einige dieser Antworten sehen verrückt aus! Codeface hat es aber geschafft! (Siehe die Antwort von @ 0xC0DEFACE hier ). Ich mag das typfreie Ausdrucksformular für Makros oder gcc-Anweisungen gegenüber dem Funktionsformular sehr, daher habe ich diese Antwort mit einer detaillierten Erklärung meiner Arbeit (dh warum dies mathematisch funktioniert) geschrieben und in zwei Formulare unterteilt ::
/// @brief ROUND_DIVIDE(numerator/denominator): round to the nearest whole integer when doing
/// *integer* division only
/// @details This works on *integers only* since it assumes integer truncation will take place automatically
/// during the division!
/// @notes The concept is this: add 1/2 to any number to get it to round to the nearest whole integer
/// after integer trunction.
/// Examples: 2.74 + 0.5 = 3.24 --> 3 when truncated
/// 2.99 + 0.5 = 3.49 --> 3 when truncated
/// 2.50 + 0.5 = 3.00 --> 3 when truncated
/// 2.49 + 0.5 = 2.99 --> 2 when truncated
/// 2.00 + 0.5 = 2.50 --> 2 when truncated
/// 1.75 + 0.5 = 2.25 --> 2 when truncated
/// To add 1/2 in integer terms, you must do it *before* the division. This is achieved by
/// adding 1/2*denominator, which is (denominator/2), to the numerator before the division.
/// ie: `rounded_division = (numer + denom/2)/denom`.
/// ==Proof==: 1/2 is the same as (denom/2)/denom. Therefore, (numer/denom) + 1/2 becomes
/// (numer/denom) + (denom/2)/denom. They have a common denominator, so combine terms and you get:
/// (numer + denom/2)/denom, which is the answer above.
/// @param[in] numerator any integer type numerator; ex: uint8_t, uint16_t, uint32_t, int8_t, int16_t, int32_t, etc
/// @param[in] denominator any integer type denominator; ex: uint8_t, uint16_t, uint32_t, int8_t, int16_t, int32_t, etc
/// @return The result of the (numerator/denominator) division rounded to the nearest *whole integer*!
#define ROUND_DIVIDE(numerator, denominator) (((numerator) + (denominator) / 2) / (denominator))
Sehen Sie ein wenig mehr auf gcc - Anweisung Ausdrücke hier .
/// @brief *gcc statement expression* form of the above macro
#define ROUND_DIVIDE2(numerator, denominator) \
({ \
__typeof__ (numerator) numerator_ = (numerator); \
__typeof__ (denominator) denominator_ = (denominator); \
numerator_ + (denominator_ / 2) / denominator_; \
})
(Hinzugefügt im März / April 2020)
#include <limits>
// Template form for C++ (with type checking to ensure only integer types are passed in!)
template <typename T>
T round_division(T numerator, T denominator)
{
// Ensure only integer types are passed in, as this round division technique does NOT work on
// floating point types since it assumes integer truncation will take place automatically
// during the division!
// - The following static assert allows all integer types, including their various `const`,
// `volatile`, and `const volatile` variations, but prohibits any floating point type
// such as `float`, `double`, and `long double`.
// - Reference page: https://en.cppreference.com/w/cpp/types/numeric_limits/is_integer
static_assert(std::numeric_limits<T>::is_integer, "Only integer types are allowed");
return (numerator + denominator/2)/denominator;
}
BASE 2 CONCEPT:
um weitere Details zu erhalten!todo: teste dies auf negative Eingaben und aktualisiere diese Antwort, wenn es funktioniert:
#define ROUND_DIVIDE(numer, denom) ((numer < 0) != (denom < 0) ? ((numer) - (denom) / 2) / (denom) : ((numer) + (denom) / 2) / (denom))
ROUND_DIVIDE(-3 , 4)
ausgewertet zu 0
, was nicht die nächste ganze Zahl ist. Die ausführlichen Erklärungen sprechen dieses Problem überhaupt nicht an. (int)round(-3.0 / 4.0)
würde zu bewerten -1
.
DIVIDE_ROUNDUP()
, DIVIDE_ROUNDDOWN()
und DIVIDE_ROUNDNEAREST()
, die alle sowohl positive als auch negative Ganzzahl-Eingaben verarbeiten. Hoffentlich gewinne ich dann deine Gegenstimme. Ich werde diese sicherlich selbst verwenden.
int divide(x,y){
int quotient = x/y;
int remainder = x%y;
if(remainder==0)
return quotient;
int tempY = divide(y,2);
if(remainder>=tempY)
quotient++;
return quotient;
}
zB 59/4 Quotient = 14, TempY = 2, Rest = 3, Rest> = TempY, daher Quotient = 15;
divide(-59, 4)
.
double a=59.0/4;
int b=59/4;
if(a-b>=0.5){
b++;
}
printf("%d",b);
Versuchen Sie es mit der mathematischen Ceil-Funktion, mit der aufgerundet wird. Mathe Decke !
Wenn Sie positive ganze Zahlen teilen, können Sie sie nach oben verschieben, dividieren und dann das Bit rechts vom realen b0 überprüfen. Mit anderen Worten, 100/8 ist 12,5, würde aber 12 zurückgeben. Wenn Sie (100 << 1) / 8 tun, können Sie b0 überprüfen und dann aufrunden, nachdem Sie das Ergebnis wieder nach unten verschoben haben.
Für einige Algorithmen benötigen Sie eine konsistente Verzerrung, wenn "am nächsten" ein Gleichstand ist.
// round-to-nearest with mid-value bias towards positive infinity
int div_nearest( int n, int d )
{
if (d<0) n*=-1, d*=-1;
return (abs(n)+((d-(n<0?1:0))>>1))/d * ((n<0)?-1:+1);
}
Dies funktioniert unabhängig vom Vorzeichen des Zählers oder Nenners.
Wenn Sie die Ergebnisse von round(N/(double)D)
(Gleitkommadivision und Rundung) abgleichen möchten , finden Sie hier einige Variationen, die alle die gleichen Ergebnisse liefern:
int div_nearest( int n, int d )
{
int r=(n<0?-1:+1)*(abs(d)>>1); // eliminates a division
// int r=((n<0)^(d<0)?-1:+1)*(d/2); // basically the same as @ericbn
// int r=(n*d<0?-1:+1)*(d/2); // small variation from @ericbn
return (n+r)/d;
}
Hinweis: Die relative Geschwindigkeit von (abs(d)>>1)
vs. (d/2)
ist wahrscheinlich plattformabhängig.
int
.
return (n+(1<<shift>>1))>>shift;
, die sich zu der Form vereinfacht (n+C)>>shift
(wo, C=(1<<shift>>1)
wenn shift
zufällig eine Konstante ist.
Im Folgenden wird der Quotient für positive und negative Operanden OHNE Gleitkomma- oder bedingte Verzweigungen korrekt auf die nächste Ganzzahl gerundet (siehe Baugruppenausgabe unten). Nimmt die Komplement-Ganzzahlen von N-Bit 2 an.
#define ASR(x) ((x) < 0 ? -1 : 0) // Compiles into a (N-1)-bit arithmetic shift right
#define ROUNDING(x,y) ( (y)/2 - (ASR((x)^(y)) & (y)))
int RoundedQuotient(int x, int y)
{
return (x + ROUNDING(x,y)) / y ;
}
Der Wert von ROUNDING hat das gleiche Vorzeichen wie die Dividende (x) und die halbe Größe des Divisors (y). Das Hinzufügen von RUNDEN zur Dividende erhöht somit deren Größe, bevor die ganzzahlige Division den resultierenden Quotienten abschneidet. Hier ist die Ausgabe des gcc-Compilers mit -O3-Optimierung für einen 32-Bit-ARM-Cortex-M4-Prozessor:
RoundedQuotient: // Input parameters: r0 = x, r1 = y
eor r2, r1, r0 // r2 = x^y
and r2, r1, r2, asr #31 // r2 = ASR(x^y) & y
add r3, r1, r1, lsr #31 // r3 = (y < 0) ? y + 1 : y
rsb r3, r2, r3, asr #1 // r3 = y/2 - (ASR(x^y) & y)
add r0, r0, r3 // r0 = x + (y/2 - (ASR(x^y) & y)
sdiv r0, r0, r1 // r0 = (x + ROUNDING(x,y)) / y
bx lr // Returns r0 = rounded quotient
Einige Alternativen zur Division durch 4
return x/4 + (x/2 % 2);
return x/4 + (x % 4 >= 2)
Oder im Allgemeinen Division durch eine Potenz von 2
return x/y + x/(y/2) % 2; // or
return (x >> i) + ((x >> i - 1) & 1); // with y = 2^i
Es funktioniert durch Aufrunden, wenn der Bruchteil ⩾ 0,5, dh die erste Ziffer ⩾ Basis / 2 ist. In der Binärdatei entspricht dies dem Hinzufügen des ersten Bruchbits zum Ergebnis
Diese Methode hat in Architekturen mit einem Flag-Register einen Vorteil, da das Übertragsflag das letzte herausgeschobene Bit enthält . Zum Beispiel auf x86 kann es optimiert werden
shr eax, i
adc eax, 0
Es kann auch problemlos erweitert werden, um vorzeichenbehaftete Ganzzahlen zu unterstützen. Beachten Sie, dass der Ausdruck für negative Zahlen lautet
(x - 1)/y + ((x - 1)/(y/2) & 1)
Wir können dafür sorgen, dass es sowohl für positive als auch für negative Werte funktioniert
int t = x + (x >> 31);
return (t >> i) + ((t >> i - 1) & 1);
Der grundlegende Algorithmus zur Rundungsteilung, wie er von früheren Mitwirkenden vorgestellt wurde, besteht darin, dem Zähler vor der Division die Hälfte des Nenners hinzuzufügen. Dies ist einfach, wenn die Eingaben ohne Vorzeichen sind, nicht ganz, wenn es sich um vorzeichenbehaftete Werte handelt. Hier sind einige Lösungen, die von GCC optimalen Code für ARM generieren (thumb-2).
Signiert / nicht signiert
inline int DivIntByUintRnd(int n, uint d)
{
int sgn = n >> (sizeof(n)*8-1); // 0 or -1
return (n + (int)(((d / 2) ^ sgn) - sgn)) / (int)d;
}
Die erste Codezeile repliziert das Zählerzeichenbit durch ein ganzes Wort und erzeugt Null (positiv) oder -1 (negativ). In der zweiten Zeile wird dieser Wert (falls negativ) verwendet, um den Rundungsterm unter Verwendung der Komplementnegation von 2 zu negieren: Komplement und Inkrement. In früheren Antworten wurde eine bedingte Anweisung verwendet oder multipliziert, um dies zu erreichen.
Signiert / Signiert
inline int DivIntRnd(int n, int d)
{
int rnd = d / 2;
return (n + ((n ^ d) < 0 ? -rnd : rnd)) / d;
}
Ich habe festgestellt, dass ich den kürzesten Code mit dem bedingten Ausdruck erhalten habe, aber nur, wenn ich dem Compiler durch Berechnung des Rundungswerts d / 2 geholfen habe. Die Verwendung der Komplementnegation von 2 ist nah:
inline int DivIntRnd(int n, int d)
{
int sgn = (n ^ d) >> (sizeof(n)*8-1); // 0 or -1
return (n + ((d ^ sgn) - sgn) / 2) / d;
}
Division durch Mächte von 2
Während die ganzzahlige Division gegen Null abschneidet, schneidet die Verschiebung gegen negative Unendlichkeit ab. Dies macht eine Rundungsverschiebung viel einfacher, da Sie den Rundungswert unabhängig vom Vorzeichen des Zählers immer addieren.
inline int ShiftIntRnd(int n, int s) { return ((n >> (s - 1)) + 1) >> 1; }
inline uint ShiftUintRnd(uint n, int s) { return ((n >> (s - 1)) + 1) >> 1; }
Der Ausdruck ist derselbe (je nach Typ wird unterschiedlicher Code generiert), sodass ein Makro oder eine überladene Funktion für beide funktionieren kann.
Die traditionelle Methode (die Art und Weise, wie die Rundungsteilung funktioniert) besteht darin, die Hälfte des Teilers 1 << (s-1) zu addieren. Stattdessen verschieben wir eine weniger, fügen eine hinzu und machen dann die letzte Schicht. Dies erspart das Erstellen eines nicht trivialen Werts (auch wenn dieser konstant ist) und das Maschinenregister, in das er eingegeben werden soll.
int sgn = n >> (sizeof(n)*8-1); // 0 or -1
: NEIN, das Verhalten ist nicht durch den C-Standard definiert. Sie solltenint sgn = ~(n < 0);
~(n < 0)
erzeugt eine weitere Anweisung. Außerdem funktioniert der ursprüngliche Ausdruck auf jeder Architektur mit 8-Bit-Bytes und Zweierkomplement, was meiner Meinung nach alle modernen Maschinen beschreibt.
Ich stieß auf die gleiche Schwierigkeit. Der folgende Code sollte für positive Ganzzahlen funktionieren.
Ich habe es noch nicht kompiliert, aber ich habe den Algorithmus in einer Google-Tabelle (ich weiß, wtf) getestet und es hat funktioniert.
unsigned int integer_div_round_nearest(unsigned int numerator, unsigned int denominator)
{
unsigned int rem;
unsigned int floor;
unsigned int denom_div_2;
// check error cases
if(denominator == 0)
return 0;
if(denominator == 1)
return numerator;
// Compute integer division and remainder
floor = numerator/denominator;
rem = numerator%denominator;
// Get the rounded value of the denominator divided by two
denom_div_2 = denominator/2;
if(denominator%2)
denom_div_2++;
// If the remainder is bigger than half of the denominator, adjust value
if(rem >= denom_div_2)
return floor+1;
else
return floor;
}
if(denominator == 1) return numerator;
. Was ist seine Aufgabe?
Sichererer C-Code (sofern Sie keine anderen Methoden zur Behandlung von / 0 haben):
return (_divisor > 0) ? ((_dividend + (_divisor - 1)) / _divisor) : _dividend;
Dies behandelt natürlich nicht die Probleme, die durch einen falschen Rückgabewert aufgrund Ihrer ungültigen Eingabedaten entstehen.