• Listen to a special audio message from Bill Roper to the Hive Workshop community (Bill is a former Vice President of Blizzard Entertainment, Producer, Designer, Musician, Voice Actor) 🔗Click here to hear his message!
  • Read Evilhog's interview with Gregory Alper, the original composer of the music for WarCraft: Orcs & Humans 🔗Click here to read the full interview.

100% accurate and pretty fast realToIndex and back

Status
Not open for further replies.
Level 8
Joined
Nov 20, 2011
Messages
202
Up to now it was not possible to cast reals to int and back without loosing accuracy and performance

But muzzel and i found some tricky way to do this:

JASS:
function realToIndex takes real r returns integer
    return r
endfunction

function cleanInt takes integer i returns integer
    return i
endfunction

function indexToReal takes integer i returns real
    return i
endfunction

function cleanReal takes real r returns real
    return r
endfunction

function testCast takes nothing returns nothing
    local integer i = cleanInt(realToIndex(123.456))
    local real r = cleanReal(indexToReal(i))
    call BJDebugMsg(R2S(r)) //prints 123.456
endfunction

Important: Ignore compiling errors, wc3 will accept it nevertheless!!!
 
Last edited:
Level 8
Joined
Nov 20, 2011
Messages
202
So does this convert a real into a pointer to a "real" structure or are reals really 32 bit floats? I keep hearing contradictory evidence with some saying that real type is implemented as a string and others that it is a float.

It is a float in IEEE representation.
For example the value 123.456 is in IEEE representaion:
01000010111101101110100101111001
If you read this value now as an integer you get:
1123477881

BJDebugMsg(I2S(realToIndex(123.456))) also prints 1123477881.
So iam pretty sure that reals aren't strings.
 
Up to now it was not possible to cast reals to int and back without loosing accuracy and performance

Is this really faster than I2R and R2I? Don't get me wrong, your method may have the accuracy benefit, but I find it difficult to believe that a function call would beat a native call. :\

EDIT: I may have misunderstood. However, what is the purpose in casting them back and forth? I'm just curious.
 
Level 14
Joined
Jun 27, 2008
Messages
1,325
cleanInt(realToIndex(real r)) simply returns an integer value which is unique for the specified real. So the function assigns an integer value to every possible real value with the guarantee that no two different reals get the same integer assigned.
This can be used to store a real in an integer variable. This might seem useless because for most purposes you could just use a real value, but for example the Wurst Generics dont support reals, so you could use this integer representation to store reals.
A different example are saveload systems where you can only store integer values. By converting the real into an integer you can store the real with its full accuracy and convert it back to a real when loading.

Note: This does not replace the R2I function which does something different. R2I (in many languages this also is called floor()) rounds the real down to the next integer. This means the conversion done by R2I does not have an inverse:
I2R(R2I(13.724)) == 13.000
Also the cleanInt(realToIndex(real r)) function does not return a integer value which is somewhat close to the reals value. You can convert it if you want:
JASS:
function convert takes integer n returns integer
    return n - (n / 8388608) * 8388608 + 8388608 / udg_powArr[n / 8388608 - 127]
endfunction
(udg_powArr[n] contains the value 2^n)

So:
JASS:
R2I(real r)
is equal to:
JASS:
convert(cleanInt(realToIndex(real r)))
and when using it like this you can even drop the clean function:
JASS:
convert(realToIndex(real r))
However this is slower than calling the native R2I.
But if you just want ANY integer representation you can use "cleanInt(realToIndex(real r))" which is even faster than R2I.

One more thing:
I2R(int i) has been found to be significantly slower than (i*1.). As these two do the exact same thing all occurences of I2R should be replaced with (i*1.).
 
Level 14
Joined
Jun 27, 2008
Messages
1,325
but well, I was instrested in how you could overcome the error in JNGP, and you could just not write anything rather than useless "Its not my problem"

Im pretty sure you cant. When testing this stuff we used plain Jass and disabled the vJass Language Support in JNGP. But this is why these kinds of posts go into the lab, because its experimental stuff that is not ready to be applied for productive stuff. So dont expect too much :>

€: oh and i think its not our problem anyway ^_°
 
Level 26
Joined
Aug 18, 2009
Messages
4,097
This is not casting between integers and floats, this is casting pointers and dereferencing them. A nice hack I might add, though I am not sure why you call it "index".

Was referring to

One more thing:
I2R(int i) has been found to be significantly slower than (i*1.). As these two do the exact same thing all occurences of I2R should be replaced with (i*1.).
 
Level 6
Joined
Aug 26, 2009
Messages
192
This can be used to get representations of inf and -inf. For NaN this doesn't seem to work...

JASS:
function cleanReal takes real r returns real
    return r
endfunction

function i2rh takes integer i returns real
    return i
endfunction

function i2r takes integer i returns real
    return cleanReal(i2rh(i))
endfunction

function testCast takes nothing returns nothing
    local integer i1 = 0x7f800000
    local integer i2 = 0xff800000
    local integer i3 = 0xffc00000
    local integer i4 = 0xff800001
    call BJDebugMsg(R2S(i2r(i1)))
    call BJDebugMsg(R2S(i2r(i2)))
    call BJDebugMsg(R2S(i2r(i3)))
    call BJDebugMsg(R2S(i2r(i4)))
endfunction

This code prints
inf
-inf
some crazy number
another crazy number
although the last two numbers are representations of NaN. We tested a few others but it seems like the R2S function really crazy or something...

edit:
Pay attention. These do NOT behave like inf or -inf from Java or other languages. Actually they have some awkward behavior.
 
Last edited:

LeP

LeP

Level 13
Joined
Feb 13, 2008
Messages
543
Let's face it: The chance of blizzard fixing this and other "hacks" is zero. So why not abuse it?

But i already do
JASS:
function log2l takes real r returns real
    local integer l = r2i(r)
    local integer e = l/0x800000
    if r <= 0 then
        return 0
    endif
    set r = i2r(0x3F800000+(l-e*0x800000))
    return e-128.666666+(2.0-r/3.0)*r
endfunction

i also tested fast inverse square root but it wasn't very fast…
 
Re-opening thread as it's been linked to by another and should be open for another discussion.

I believe the way to fix pJass optimization breaking the script is to just add a useless local declaration or redundant return statement.

This could be useful to represent a perfect comparator, although as looking_for_help has discovered, "not real != otherReal" seems to do the trick, too.

Although, real comparisons are apparently slow, so if you are going to do a lot of conparing and not a lot of typecasting this could be more optimal.
 
Level 14
Joined
Dec 12, 2012
Messages
1,007
Re-opening thread as it's been linked to by another and should be open for another discussion.

I believe the way to fix pJass optimization breaking the script is to just add a useless local declaration or redundant return statement.

The loop-return hack does the trick (its not really an optimization problem in vJass, but requires something more like the return bug, seems vJass is a bit stricter in this case). With that it works in vJass too.

This could be useful to represent a perfect comparator, although as looking_for_help has discovered, "not real != otherReal" seems to do the trick, too.

Although, real comparisons are apparently slow, so if you are going to do a lot of conparing and not a lot of typecasting this could be more optimal.

It will be especially usefull to evaluate further properties of reals in Wc3. So even if it is not used in a final map, it can be used beforehand to get new insights.
 
Status
Not open for further replies.
Top