"John Matthews" <jm5...@...> wrote:
> praveen indian85 <praveen_indian85@> wrote:
> >            dec=dec+temp*pow(2,i);
> 
> pow() takes double arguments and returns a double.
> The following would be more appropriate:
> 
>   dec += temp * (1 << i);
> 
> BTW is (int)pow(2, i) guaranteed to return the same
> as (1 << i) for say integer i=0..15 (assuming 32 bit
> int)?

Technically, you only need an int with at least 16 value
bits for (1 << i) to be well defined for i in [0..15].

But to answer your question, no, the standard doesn't
actually guarantee that. It says:

  "The accuracy of the floating-point operations (+, -,
  *, /) and of the library functions in <math.h> and
  <complex.h> that return floating-point results is
  implementation-defined, ..."

So it's a quality of implementation (QoI) issue. That said,
if you do find an implementation where the property doesn't
hold, you'll likely find that it's a contrived system, not
a serious product.

But as you've noticed, the two expressions are different
operations if i equals or exceeds the number of value bits.
The behaviour is undefined, but ordinary systems tend not
to trap, and instead produce deterministic values. Which
they are perfectly allowed to do.

However, unless a compiler can determine that i is indeed
within appropriate range, then it likely won't optimise
such a call to pow. Examine the following...

  % type pow.c
  #include <math.h>
  #include <stdio.h>
  
  int foo(int x) { return pow(2, x); }
  int bar(int x) { return 1 << x; }
  
  int main(void)
  {
    int i;
    for (i = 0; i < 15; i++)
      if (foo(i) != bar(i))
        printf("fail: %d\n", i);
    return 0;
  }
  
  % acc -S pow.c
  
  % type pow.s
          .file   "pow.c"
          .section .text
          .p2align 4,,15
  .globl _bar
  _bar:
          pushl   %ebp
          movl    $1, %eax
          movl    %esp, %ebp
          movl    8(%ebp), %ecx
          popl    %ebp
          sall    %cl, %eax
          ret
          .p2align 4,,15
  .globl _foo
  _foo:
          pushl   %ebp
          movl    %esp, %ebp
          subl    $24, %esp
          fildl   8(%ebp)
          fstpl   -8(%ebp)
          movl    -8(%ebp), %eax
          movl    -4(%ebp), %edx
          pushl   %edx
          pushl   %eax
          pushl   $1073741824
          pushl   $0
          call    _pow
          fnstcw  -18(%ebp)
          movw    -18(%ebp), %ax
          fstpl   -16(%ebp)
          movb    $12, %ah
          movw    %ax, -20(%ebp)
          fldl    -16(%ebp)
          fldcw   -20(%ebp)
          fistpl  -24(%ebp)
          fldcw   -18(%ebp)
          movl    -24(%ebp), %eax
          leave
          ret
          .p2align 4,,15
  .globl _main
  _main:
          leal    4(%esp), %ecx
          andl    $-16, %esp
          xorl    %eax, %eax
          pushl   -4(%ecx)
          pushl   %ebp
          movl    %esp, %ebp
          pushl   %ecx
          popl    %ecx
          popl    %ebp
          leal    -4(%ecx), %esp
          ret
          .ident  "GCC: (GNU) 4.3.2"

You'll notice that my implementation did not optimise
out the call to pow in foo().[1] However main() is
optimised effectively to a no-op since the compiler
was able to recognise that foo(i) will indeed equal
bar(i) for the iterated values of i!

[1] Since it has external linkage. See what happens
in gcc if you change it to static (internal linkage)
and turn up the optimisation level. :-)

-- 
Peter

Reply via email to