Sign in to follow this  

Bug with log2, assembler guru help needed

This topic is 2569 days old which is more than the 365 day threshold we allow for new replies. Please post a new topic.

If you intended to correct an error in the post then please contact us.

Recommended Posts

Hi, I have a Log2 method which have inconsistent result between debug & release

here's the c++ code

u32 Log2( float _f )
{
#ifdef XTM_MACOSX
return ilogbf( _f );
#else
const float b = 1.4426950f; // this is 1.0f / log( 2.0f );
float r = log( _f ) * b;
return ((u32)r);
#endif
}



Here's the debug asm

?Log2@xtm@@YAKM@Z PROC ; xtm::Log2

; 28 : {

push ebp
mov ebp, esp
sub esp, 24 ; 00000018H
mov eax, -858993460 ; ccccccccH
mov DWORD PTR [ebp-24], eax
mov DWORD PTR [ebp-20], eax
mov DWORD PTR [ebp-16], eax
mov DWORD PTR [ebp-12], eax
mov DWORD PTR [ebp-8], eax
mov DWORD PTR [ebp-4], eax

; 29 : #ifdef XTM_MACOSX
; 30 : return ilogbf( _f );
; 31 : #else
; 32 : //TODO bug inconsistent calculation between release & debug ( IEEE Strict & fast floating point ? examine asm )
; 33 :
; 34 : //return log( _f ) / log( 2.0f );
; 35 : const float b = 1.4426950f; // 1.0f / log( 2.0f );

movss xmm0, DWORD PTR __real@3fb8aa3b
movss DWORD PTR _b$[ebp], xmm0

; 36 : float r = log( _f ) * b;

push ecx
movss xmm0, DWORD PTR __f$[ebp]
movss DWORD PTR [esp], xmm0
call ?log@@YAMM@Z ; log
add esp, 4
fmul DWORD PTR _b$[ebp]
fstp DWORD PTR _r$[ebp]

; 37 : //printf( "log(%f) = %f (%u)\n", _f, r, (u32)r );
; 38 : return ((u32)r);

fld DWORD PTR _r$[ebp]
fnstcw WORD PTR tv74[ebp]
movzx eax, WORD PTR tv74[ebp]
or eax, 3072 ; 00000c00H
mov DWORD PTR tv77[ebp], eax
fldcw WORD PTR tv77[ebp]
fistp QWORD PTR tv79[ebp]
fldcw WORD PTR tv74[ebp]
mov eax, DWORD PTR tv79[ebp]

; 39 : #endif
; 40 : }

add esp, 24 ; 00000018H
cmp ebp, esp
call __RTC_CheckEsp
mov esp, ebp
pop ebp
ret 0


And the release asm:


?Log2@xtm@@YAKM@Z PROC ; xtm::Log2

; 28 : {

push ebp
mov ebp, esp
sub esp, 8

; 29 : #ifdef XTM_MACOSX
; 30 : return ilogbf( _f );
; 31 : #else
; 32 : //TODO bug inconsistent calculation between release & debug ( IEEE Strict & fast floating point ? examine asm )
; 33 :
; 34 : //return log( _f ) / log( 2.0f );
; 35 : const float b = 1.4426950f; // 1.0f / log( 2.0f );
; 36 : float r = log( _f ) * b;
; 37 : //printf( "log(%f) = %f (%u)\n", _f, r, (u32)r );
; 38 : return ((u32)r);

fld DWORD PTR __f$[ebp]
fldln2
fxch ST(1)
fnstcw WORD PTR tv78[ebp]
fyl2x
movzx eax, WORD PTR tv78[ebp]
or eax, 3072 ; 00000c00H
mov DWORD PTR tv80[ebp], eax
fmul DWORD PTR __real@3fb8aa3b
fldcw WORD PTR tv80[ebp]
fistp QWORD PTR tv64[ebp]
mov eax, DWORD PTR tv64[ebp]
fldcw WORD PTR tv78[ebp]

; 39 : #endif
; 40 : }

mov esp, ebp
pop ebp
ret 0


In debug Log2( 1024.0f ) returns 9 and in release 10

I'm compiling under VS2010 with the following settings:

Debug Release
Optim Disabled Full
Enable Intrinsic Functions No Yes
Enable Ehanced Instr. set SSE2 SSE2
Floating point model Fast Fast
Floating Point Exceptions No No

Can you see what's wrong here ? I would greatly appreciate any help with this issue

Share this post


Link to post
Share on other sites
It seems your release build actually calculates log2 with an ASM instruction, then converts that to the natural logarithm, and then multiplies with your b to convert back to log2.
I guess that floating point inaccuracy leads to something like 9.999f which is rounded down when converted to an integer.

(Edited)

Share this post


Link to post
Share on other sites
Are you only interested in return the integer part (floor:ing away the decimals) of a log2 operation of a 32-bit floating point value?
If that is the case, using bit manipulations on the float representation is easier, since the exponent is directly stored in the float itself.

Here is some pseudocode that should work with 32-bit float, including a little bit of error checking

in = (int)_f
If in&&0x80000000 == 0x80000000 //Return NaN if input is negative
return 0x7f800001 //Return NaN
else if (in&&0x7f800000 == 0x7f800000) &&(in&&0x007fffff != 0) //Return NaN if input NaN
return 0x7f800001 //NaN
else if in == 0x7f800000
return 0x7f800000
else
return in>>23 //Return exponent of 32 bit float


http://en.wikipedia.org/wiki/Single_precision_floating-point_format
(It's the 8 green bits in the figure you are after)


Share this post


Link to post
Share on other sites
Awesome ! Thanks !
What I needed was a fast way to get the number of mipmaps for a given texture size ( for a 1024x1024 that is 11 mip levels) historicaly I also used this function for level of detail on a procedural terrain generator it is why the input is a float.

But I think I'll make a separate version with integer math only. I believe there is an asm instruction that tell you the "position" of the most significant bit that is set to 1.

Eg binary value 00010000 (16 in base 10) would result in 4

Do you know a (portable if possible) way to do this ?
I could shift the value one bit at a time in a loop. But I'm trying to avoid loops for that purpose.

Share this post


Link to post
Share on other sites
From: http://stackoverflow.com/questions/994593/how-to-do-an-integer-log2-in-c


#include <stdint.h>
static inline uint32_t log2(const uint32_t x) {
uint32_t y;
asm ( "\tbsr %1, %0\n"
: "=r"(y)
: "r" (x)
);
return y;
}

Share this post


Link to post
Share on other sites
Thanks a thousand times for your help ! :)

By the way, just to introduce myself and my work, I'm an "ex professional game developer" (although not very sharp in the asm field) I retired to work on my own project which is a battlefield like game, but oriented toward simulation ( eg plane physics use a flight model similar to X-plane )

The engine is cross platform :
- iPhone iPad
- Linux
- Windows ( GL & DX9 through DX11)
- MacOSX


The terrain is a hires (1meter resolution) satellite data of Reunion Island ( which is very mountainous)

Well ... See you soon in the IOTD !

[Edited by - Florent 974 on December 4, 2010 7:10:01 AM]

Share this post


Link to post
Share on other sites

This topic is 2569 days old which is more than the 365 day threshold we allow for new replies. Please post a new topic.

If you intended to correct an error in the post then please contact us.

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now

Sign in to follow this