#include #include #include #include #include uint64_t absdiff(uint64_t x, uint64_t y) { return x >= y ? x - y : y - x; } void approxu(uint32_t zv, uint32_t nv, uint16_t *za, uint16_t *na) { uint32_t z = zv, n = nv, q, zt, nt; uint16_t z0 = 0, n0 = 1, z1 = 1, n1 = 0; // Kettenbruchentwicklung while (n) { q = z / n; nt = z - q * n; z = n; n = nt; nt = q * n1 + n0; zt = q * z1 + z0; q = 0; // Überschreitet der neue Zähler oder Nenner mit dem zuletzt berechneten // Koeffizienten q das obere Limit, wird das nächstkleinere q bestimmt, für // das dies nicht der Fall ist. Daraus ergibt sich möglicherweise eine // bessere Näherung. // if (zt > INT16_MAX) { q = (INT16_MAX - z0) / z1; break; } if (nt > INT16_MAX) { q = (INT16_MAX - n0) / n1; break; } n0 = n1; n1 = nt; z0 = z1; z1 = zt; } *za = z1; *na = n1; if (q) { // Falls die Schleife wegen Überschreiten des Limits abgebrochen wurde, // wird die bis dahin beste Näherung z1/n1 möglicherweise durch die // Hinzunahme es oben bestimmten Ersatzkoeffizienten noch weiter // verbessert. Ob dies der Fall ist, wird durch den Vergleich der // jeweiligen Abweichungen vom vorgegebenen Bruch zv/nv entschieden. z0 = q * z1 + z0; n0 = q * n1 + n0; if ( n1 * absdiff((uint64_t)zv * n0, (uint64_t)nv * z0) < n0 * absdiff((uint64_t)zv * n1, (uint64_t)nv * z1)) { *za = z0; *na = n0; } } } // Wrapper um approxu für vorzeichenbehaftete Brüche void approxs(int32_t zv, int32_t nv, int16_t *za, int16_t *na) { bool negative = false; if (zv < 0) { negative = true; zv = -(uint32_t)zv; } if (nv < 0) { negative = !negative; nv = -(uint32_t)nv; } uint16_t zau, nau; approxu(zv, nv, &zau, &nau); *na = nau; *za = negative ? -zau : zau; } int main(int argc, char **argv) { int32_t zv = atoi(argv[1]), nv = atoi(argv[2]); int16_t za, na; approxs(zv, nv, &za, &na); printf("%d/%d\n", za, na); return 0; }