bitcoin / bitcoin

Bitcoin Core integration/staging tree
https://bitcoincore.org/en/download
MIT License
79.83k stars 36.47k forks source link

Multiplication vs Division #22825

Closed ghost closed 3 years ago

ghost commented 3 years ago

I was reading about multiplication being faster than division in C++: https://stackoverflow.com/a/17883577/

99% of the regular contributors in this repository know C++ better than me so I think this must have already been discussed or considered while doing calculations although I couldn't find anything in doc/developer-notes.md

Division is done at lot of places which could be replaced with multiplication. Are there any downsides?

Example: GetMinFee() in src/txmempool.cpp

CFeeRate CTxMemPool::GetMinFee(size_t sizelimit) const {
    LOCK(cs);
    if (!blockSinceLastRollingFeeBump || rollingMinimumFeeRate == 0)
        return CFeeRate(llround(rollingMinimumFeeRate));

    int64_t time = GetTime();
    if (time > lastRollingFeeUpdate + 10) {
        double halflife = ROLLING_FEE_HALFLIFE;
-        if (DynamicMemoryUsage() < sizelimit / 4)
+        if (DynamicMemoryUsage() < sizelimit * 0.25)
-            halflife /= 4;
+            halflife *= 0.25;
-        else if (DynamicMemoryUsage() < sizelimit / 2)
+        else if (DynamicMemoryUsage() < sizelimit * 0.5)
-            halflife /= 2;
+           halflife *= 0.5;

        rollingMinimumFeeRate = rollingMinimumFeeRate / pow(2.0, (time - lastRollingFeeUpdate) / halflife);
        lastRollingFeeUpdate = time;

-        if (rollingMinimumFeeRate < (double)incrementalRelayFee.GetFeePerK() / 2) {
+        if (rollingMinimumFeeRate < (double)incrementalRelayFee.GetFeePerK() * 0.5) {
            rollingMinimumFeeRate = 0;
            return CFeeRate(0);
        }
    }
    return std::max(CFeeRate(llround(rollingMinimumFeeRate)), incrementalRelayFee);
}
sipa commented 3 years ago

What you read is right, and it's not restricted to C++. CPUs are significantly slower at division than multiplication. However, the issue only applies when you're dividing by a variable.

Whenever you're dividing by a constant that's known at compile time, the compiler will just convert it to a multiplication at optimization time, similar to what you're doing by hand here.

Furthermore, some of the cases you're highlighting are divisions by an integer; you can't replace them by a multiplication with a floating point number (the result will be a different data type). It is possible to convert integer division by a constant to something faster as well, but it's a little more complicated (depending on the situation, it may involve multiplications, shifts, or a combination of the two).

Lastly, none of the cases you point out are performance critical. It's better to focus optimization efforts on places where it matters.

ghost commented 3 years ago

Thanks @sipa that answers my question. Will close the issue.