0

Lets say I have a double a = 0.3;. How would I be able to change the exponent of the variable, without using math functions like pow(), or multiplying it manually.

I am guessing I would have to acces the memory addres of the variable using pointers, find the exponent and change it manualy. But how would I accomplish this?

Note, that this is on a 8-bit system, and I am trying to find a faster way to multiply the number by 10^12, 10^9, 10^6 or 10^3.

Best regards!

user1806687
  • 934
  • 1
  • 10
  • 27
  • 2
    I don't think you're going to have much success. The exponent part of of a typical floating-point is a *binary* exponent, not one in base 10. – unwind Sep 07 '14 at 15:18
  • Seeing as a `double` is a *binary* floating point number, adjusting the exponent bits won't help multiplying by powers of ten, only by powers of two. –  Sep 07 '14 at 15:19
  • Do you need an accurate result, or would an approximation be good enough for you? – barak manos Sep 07 '14 at 15:20
  • 1
    As others have said, bit-fiddling won't help you here. But you can probably speed up your calculation if you don't use the `pow` function to calculate your factors 10^x. (If you are doing that now, that is.) – M Oehm Sep 07 '14 at 15:22
  • @barak manos I would need an accurate result. – user1806687 Sep 07 '14 at 15:24
  • @MOehm I am using pow() function. So, how would I calculate the result? – user1806687 Sep 07 '14 at 15:25
  • 1
    @user1806687: You could use a look-up table, e.g.: `double decpow[] = {1, 10, 100, 1000, ...}` and use `decpow[x]` instead of `pow(10, x)`. (This requires non-negative integer values for `x`, of course. But there are similar solutions that depend on what you need. It seems that you use only a few powers of ten that correlate with unit prefixes like kilo-, mega-, etc.) – M Oehm Sep 07 '14 at 15:29

3 Answers3

2

Multiplying a number by 10 is the equivalent of

  • a) Multiplying the original number by 2
  • b) Multiplying the original number by 8
  • c) Adding the results of (a) and (b).

This works because to is binary 1010.

One approach would therefore be to increment the exponent (for (a)), add 3 to the exponent (for (b)), then add the results.

To multiply by 10^n, repeat the above n times. Alternatively work out the binary representation of 1,000, 1,000,000, etc, and add the relevant 1s. You may make things easier by noting that 1000 for instance 1024 (for instance) is 1024 - 16 - 8, i.e.

  • a) Add 10 to the exponent of the original to multiply by 1024
  • b) Add 4 to the exponent of the original to multiply by 16
  • c) Add 3 to the exponent of the original to multiply by 8
  • d) From (a) subtract (b) and (c) to get the answer.

Again, you can do that multiple times for 10^6, 10^9 etc.

For a quick approximation and powers of n which are multiples of 3, just add 10n/3 to the exponent (as 1024 ~= 1000)

abligh
  • 24,573
  • 4
  • 47
  • 84
2

Note that a*10^3 = a*1000 = a*1024 - a*16 - a*8 = a*2^10 - a*2^4 - a*2^3.

So you can calculate a*10^3 as follows:

  • Read the 11 exponent bits into int exp

  • Read the 52 fraction bits into double frac

  • Calculate double x with exp+10 as the exponent and frac as the fraction

  • Calculate double y with exp+4 as the exponent and frac as the fraction

  • Calculate double z with exp+3 as the exponent and frac as the fraction

  • Calculate the output as x-y-z, and don't forget to add the sign bit if a < 0

You can use a similar method for the other options (a*10^6, a*10^9 and a*10^12)...


Here is how you can do the whole thing in a "clean" manner:

double MulBy1000(double a)
{
    double x = a;
    double y = a;
    double z = a;

    unsigned long long* px = (unsigned long long*)&x;
    unsigned long long* py = (unsigned long long*)&y;
    unsigned long long* pz = (unsigned long long*)&z;

    *px += 10ULL << 52;
    *py +=  4ULL << 52;
    *pz +=  3ULL << 52;

    return x - y - z;
}

Please note that I'm not sure whether or not this code breaks strict-aliasing rules.

barak manos
  • 29,648
  • 10
  • 62
  • 114
1

For fun a simple recursive solution.

double ScalePower10(double x, unsigned power) {
    if (power <= 1) {
      if (power == 0) return x;
      return x * 10.0;
    }
    double y = ScalePower10(x, power/2);
    y = y*y;
    if (power%2) y *= 10.0;
    return y;
  }
chux - Reinstate Monica
  • 143,097
  • 13
  • 135
  • 256
  • Hi Chux. I think that OP is (implicitly) trying to avoid floating-point operations. In addition to that, although your solution is general for all possible exponents, I think that OP is asking for a very specific solution (for `a*10^3`, `a*10^6`, `a*10^9` and `a*10^12`). Given that fact, OP is asking for an optimized solution, i.e., best performance for the price of a non-generic solution. – barak manos Sep 07 '14 at 15:47