I want to get numerator and denominator from decimal and then simplify both numerator and denominator. For example, if decimal is 0.05, then numerator and denominator should be 1/20. Preferably without loops/iterations or least amount of those and without memory heap.
I'm currently using this code, but it results in 0/1 rather than expected 1/20.
        public Fraction(double chance) {
            long num = 0;
            long den = 1;
            unchecked {
                ulong bitwiseRepr = BitConverter.DoubleToUInt64Bits(chance);
                ulong signBit = bitwiseRepr >> 63;
                ulong expBits = bitwiseRepr >> 52;
                ulong mntsBits = bitwiseRepr & 0x7FFFFFFFFF;
                long signFactor = signBit == 1 ? -1 : 1;
                if (expBits == 0x0000 || expBits == 0x0800) { // +0, -0
                    goto NormalWay;
                }
                else if (expBits == 0x07FF || expBits == 0x0FFF) { // +Inf, -Inf
                    num = 0;
                    den = signFactor;
                    goto NormalWay;
                }
                else if (expBits == 0x07FFF) { // NaN
                    num = long.MaxValue;
                    den = 0;
                    goto NormalWay;
                }
                long significand = (long)((1u << 52) | mntsBits);
                int nTrailizingZeros = CountTrailingZeroes(significand);
                significand >>= nTrailizingZeros;
                int exp = (int)expBits - 127 - 52 + nTrailizingZeros;
                if (exp < 0) {
                    num = significand;
                    den = 1 << -exp;
                }
                else {
                    num = signFactor * significand * (1 << exp);
                    den = 1;
                }
                goto NormalWay;
            }
        NormalWay:
            numerator = num;
            denominator = den;
            Normalize();
        }
        private static int CountTrailingZeroes(long v) {
            int counter = 0;
            while (counter < 64 && (v & 1u) == 0) {
                v >>= 1;
            counter++;
            }
            return counter;
        }
        [MethodImpl(MethodImplOptions.AggressiveOptimization | MethodImplOptions.AggressiveInlining)]
        public void Normalize() {
            bool numeratorIsNegative = numerator < 0;
            bool denominatorIsNegative = denominator < 0;
            if (numeratorIsNegative) {
                numerator *= -1;
            }
            if (denominatorIsNegative) {
                denominator *= -1;
            }
            if (numerator > long.MaxValue / 2 && denominator > long.MaxValue / 2) {
                throw new ArithmeticException($"Numerator or denominator are greater than {long.MaxValue / 2} or lesser than {-long.MaxValue / 2}.");
            }
            numerator += denominator;
            Reduce(GCD(numerator, denominator));
            Reduce(Math.Sign(denominator));
            numerator %= denominator;
            if (numeratorIsNegative) {
                numerator *= -1;
            }
            if (denominatorIsNegative) {
                denominator *= -1;
            }
        }
        [MethodImpl(MethodImplOptions.AggressiveOptimization | MethodImplOptions.AggressiveInlining)]
        private void Reduce(long x) {
            numerator /= x;
            denominator /= x;
        }
        [MethodImpl(MethodImplOptions.AggressiveOptimization | MethodImplOptions.AggressiveInlining)]
        private static long GCD(long a, long b) {
            while (b != 0) {
                long t = b;
                b = a % b;
                a = t;
            }
            return a;
        }
Current code is also going to be less acurate cause it works just for doubles (yet).