/** 64-Bit-Integer Skalieren: Multiplizieren und Dividieren (korrekt gerundet) * * ueberlaufsicher/saettigend * @param[in] in * @param[in] z Zaehler * @param[in] n Nenner * @return a*z/n korrekt gerundet */ int64_t scale_s64(int64_t in, int32_t z, int32_t n) { assert( n != 0 ); /* Zwischenvariablen */ uint64_t uin; uint32_t uz; uint32_t un; /* Vorzeichenbehandlung */ bool negative = false; if( in < 0 ) { if( in == INT64_MIN ) uin = (uint64_t)INT64_MAX + 1; else uin = -in; negative = !negative; } else { uin = in; } if( z < 0 ) { if( z == INT32_MIN ) uz = (uint32_t)INT32_MAX + 1; else uz = -z; negative = !negative; } else { uz = z; } if( n < 0 ) { if( n == INT32_MIN ) un = (uint32_t)INT32_MAX + 1; else un = -n; negative = !negative; } else { un = n; } /* Ganzzahlig teilbarer Anteil; a ≤ in ≤ INT64_MAX , groesster Wert fuer n = 1 */ uint64_t a = uin/un; /* Rest; r ≤ in ≤ INT64_MAX, r ≤ n ≤ INT32_MAX */ uint64_t r = uin%un; /* Loewenanteil, kann ueberlaufen, dann a * uz < a und a * uz < uz */ a *= uz; bool overflow0 = a < uz; /* Max. 2 * INT32_MAX */ r *= uz; /* Max. 2,5 * INT32_MAX */ r += un/2; /* Kein Ueberlauf */ r /= un; /* Ueberlauf moeglich, dann a < r */ a += r; bool overflow1 = a < r; /* Ueberlauf ueber INT64_MAX / -(INT64_MIN+1) Fuer Ergebnis INT64_MIN trotzdem korrekter Rueckgabewert */ bool overflow2 = a > ((uint64_t) INT64_MAX); if( negative ) { if( overflow0 || overflow1 || overflow2 ) { return INT64_MIN; } else { return -((uint64_t) a); } } else { if( overflow0 || overflow1 || overflow2 ) { return INT64_MAX; } else { return a; } } }