/** 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 ); int32_t t = in>>32; bool isnegative = (t ^ z ^ n) & INT32_MIN; /* a = in/n kann nur ueberlaufen fuer INT64_MIN */ if( in == INT64_MIN ) { if( z == n ) /* Bruch = 1 -> kein Ueberlauf */ { return INT64_MIN; } else if( n == INT32_MIN && z == INT32_MAX ) /* Kein Ueberlauf, 2^63 - 2^32 */ { return INT64_MAX + INT32_MIN + 1; } else if( n == INT32_MAX && z == INT32_MIN ) /* Ueberlauf */ { return INT64_MAX; } else if( z == -n ) /* Ueberlauf */ { return INT64_MAX; } else if( n == -1 ) /* Ueberlauf */ { return INT64_MAX; } } /* Ganzzahlig teilbarer Anteil; a ≤ in ≤ INT64_MAX, betragsmaessig groesste Werte fuer n = 1|-2 */ int64_t a = in/n; /* Rest; r ≤ in ≤ INT64_MAX, r ≤ n ≤ INT32_MAX */ int64_t r = in%n; /* Loewenanteil, kann ueberlaufen, dann Ergebnis gesaettigt */ static_assert( sizeof(int64_t) == sizeof(long long int) , "int type"); bool overflow0 = __builtin_smulll_overflow(a, z, &a); /* Max. ±2 * INT32_MAX */ r *= z; /* Max. ±2,5 * INT32_MAX */ if( isnegative ) r -= n/2; else r += n/2; /* Kein Ueberlauf */ r /= n; /* Ueberlauf moeglich, dann Ergebnis gesaettigt */ bool overflow1 = __builtin_saddll_overflow(a, r, &a); if( overflow0 || overflow1 ) { if( isnegative ) return INT64_MIN; else return INT64_MAX; } else { return a; } }