/** 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;
        }
    }
}