GLSL में दोहरे सटीक प्रकारों के लिए pow फ़ंक्शन नहीं है। इस फ़ंक्शन के शास्त्रीय कार्यान्वयन रिकर्सन का उपयोग करते हैं। चूंकि जीएलएसएल में रिकर्सन की अनुमति नहीं है, इसलिए मुझे रिकर्सन मुक्त कार्यान्वयन की आवश्यकता है।

मुझे exp फ़ंक्शन की भी आवश्यकता है।

2
Jhonny007 9 पद 2019, 18:36

1 उत्तर

सबसे बढ़िया उत्तर

इस समस्या को केवल दो उप-समस्याओं में विभाजित करके हल किया जा सकता है।

  1. घातांक के पूरे और भिन्नात्मक भाग को अलग करें
  2. पूरे भाग के साथ शक्ति की गणना करें (जो कि मामूली है)
  3. भिन्नात्मक भाग के साथ शक्ति की गणना करें (एक सन्निकटन का उपयोग करके)
  4. परिणाम गुणा करें
  5. यदि प्रारंभिक घातांक ऋणात्मक था तो परिणाम को उल्टा करें
/// This is a simple non recursive implementation for pow, where the exponent is an integer.
double pow(double base, int power) {
    double res = 1.0;// Initialize result

    while (power > 0.0) {
        // If power is odd, multiply x with result
        if (power % 2 == 1) {
            res *= base;
        }

        // n must be even now
        power /= 2;
        base *= base;// Change x to x^2
    }

    return res;
}

// The desired precision. More precision results in slower execution.
const double EPSILON = 0.00000001;

double pow(double base, double power) {
    // We want to ignore negative exponents for now. We invert our result at the if necessary.
    bool negative = power < 0.0LF;
    if (negative) {
        power *= -1.0LF;
    }

    // Seperate the whole and fractional parts.
    double fraction = power - int(power);
    int integer = int(power - fraction);

    // The whole part is easily calculated.
    double intPow = pow(base, integer);

    // The fractional part uses an approximation method.
    double low = 0.0LF;
    double high = 1.0LF;

    double sqr = sqrt(base);
    double acc = sqr;
    double mid = high / 2.0LF;

    while (abs(mid - fraction) > EPSILON) {
        sqr = sqrt(sqr);

        if (mid <= fraction) {
            low = mid;
            acc *= sqr;
        } else {
            high = mid;
            acc *= (1.0LF / sqr);
        }

        mid = (low + high) / 2.0LF;
    }

    // Exponential rules allow us to simply multiply our results.
    double result = intPow * acc;

    // If we started with a negative exponent we invert the result.
    if (negative) {
        return 1.0LF / result;
    }

    return result;
}

const double E = 2.7182818284590452353602874LF;

/// e^x is as simple as that.
double exp(double power) { return pow(E, power); }

प्रदर्शन

exp(random(0.0, 100.0)) के लिए औसत पुनरावृत्तियां:

EPSILON = 0.0001     -> 16.0763
EPSILON = 0.00001    -> 19.4108
EPSILON = 0.000001   -> 22.6639
EPSILON = 0.0000001  -> 26.0477
EPSILON = 0.00000001 -> 29.3929
4
Jhonny007 9 पद 2019, 18:47