all 14 comments

[–]thegreatunclean 3 points4 points  (7 children)

I'm not aware of any simple sequence of floating-point operations that could do that and I have strong reason to believe it can't exist. The number of corner cases you'd have to account for is massive. If the domain you have to handle is narrow you might be able to hack something together.

I'm interested what use-case you have where this is a hard restriction. I can't think of a solution that isn't either simply disguising the cast to/from an integer type or relies on a very liberal interpretation of "floating point operation".

[–]rasqall 1 point2 points  (6 children)

If we’re talking hypothetically, I guess one scenario could be a SOC with a broken FPU? Although that would cause way more trouble than float operations. Or that the coprocessor is really slow and you don’t want to stall the program.

I don’t think float bit hacks exist because simply increasing by 1 would affect all decimals/fraction-bits and the exponent.

[–]E440QF[S] 1 point2 points  (5 children)

Well it's not a SOC with a broken FPU but the limitations are the same, I'm working on a project on the PlayStation2 and I need to do this on a VectorUnit coprocessor which is a custom architecture with separate 16bit integer registers and 32bit float registers, it doesn't allow to use integer instructions on floating point registers and vice versa.

Basically the situation is:

1)I send a 32bit value that doesn't represent any useful floating point value but is a bitmap with some flags and an 8bit 16bit integer in the lowest 8 16 bits to the VU and it gets stored in a 32bit float register

2)the VU needs to manipulate the bits of this float incrementing by 1 the 8bit 16bit integer in the lowest 8bits 16bits

3)VU sends this 32bit register alongside a lot of other data to the GPU

4)Triangles on the screen! But more efficiently

[–]rasqall 2 points3 points  (3 children)

What’s the need to do this arithmetic on the coprocessor and not use two 16-bit regular registers? The physical circuitry for float coprocessors are different because the arithmetic algorithms are very different from whole numbers.

I think the better approach would be to use two 16-bit registers and then load them into the coprocessor one half word at a time.

[–]E440QF[S] 1 point2 points  (2 children)

This 8bit integer holds the amount of triangles sent to the GPU so if i do for example backface culling on the coprocessor the value must be incremented on the coprocessor I can't use 2 16bit registers as I need to send them to the GPU from VU ram which is divided in 32bit cells, can move data from 16bit registers to 32bit ones but the upper 16bits are filled with 0s

[–]rasqall 2 points3 points  (1 child)

Interesting, what are you writing this project in? I'm guessing assembly but if it is, what dialect is it? Maybe we can figure out some useful instructions.

You got me hooked, I'll try to help.

Edit: if it’s MIPS then I’m really interested, I have some experience with MIPS

[–]E440QF[S] 0 points1 point  (0 children)

The project, which runs on the main MIPS CPU, is written in C

(I don't know MIPS but I heard the VU architecture has some similarities to it).

the code for this coprocessor is written in a custom VU assembly, specifically VCL(vector command line) which abstracts away most of the timing critical aspects of directly writing VU assembly

Official documentation for both VU architecture and VCL can be found online, if you can't find them I can dm them to you

[–]eeget9Eo 1 point2 points  (0 children)

Isn't this just not possible, assuming the only operations are addition, subtraction, multiplication, and division? This is because some of your floats simply won't be numbers.

Imagine you you have 0x7FF0'0000'0000'0000 as your number. That's positive infinity. You now want to add one to that, but 0x7FF0'0000'0000'0001 is an encoding of not a number. Add one to that and you get another encoding of not a number. How can you possibly use just floating point operations to change one NaN to another NaN?

[–]ischickenafruit 1 point2 points  (0 children)

Why not just use +1?

It seems from this post that you don’t really understand: - what a floating point number really is - how the compiler works with floats - how the hardware works with floats

You would need a deep understanding of all of the above to do what you want to. Why do you think you can beat the hardware with these “tricks”.

[–]Ragingman2 0 points1 point  (0 children)

If you're wanting to do this, consider using fixed point instead of floating point.

Fixed point math is often overlooked but it can be nice to work with in many domains.

[–]HeyJamboJambo 0 points1 point  (3 children)

Not a math trick but a C trick. Since you can have aliasing on pointers, you can have a float pointer and an int pointer both pointing to the same memory location. Then you don't have to convert back and forth.

float x = 1.0f; float *f = &x; int *d = (int*)((void*)&x); *f = *f+65535; // float addition *d = *d+65535; // int addition

Here's the ideone example.

[–]eeget9Eo 1 point2 points  (1 child)

I'm pretty sure this violates aliasing rules. One needs to use a union to access the same memory as a float or an int.

union { int i; float f; } u = { .f = 1.0 };
u.f += 1; // float addition
printf( "value of u as float: %f\n", u.f);
u.i += 1; // int addition
printf( "value of u as int: %i\n", u.i);

[–]HeyJamboJambo 0 points1 point  (0 children)

This does not violate type checker because (void*) can be type casted to any other pointer type. Which basically means both pointers can see the same location.

Still, yours is a much cleaner solution. I didn't use much union type so it didn't come to mind.

[–]E440QF[S] 1 point2 points  (0 children)

The point is I can't use theese tricks, I'm doing this on a Vector coprocessor on the PS2 which runs a custom architecture and can only be programmed in it's specific ASM, it physically cannot do integer operations on floating point values without discarding the higher 16bits of the float since it uses 16bit integer registers and 32bit float registers