Convert float to short with minimal loss of precision

I have this sine wave that generates floating point values ​​(like 0.37885), but I want them to be shorts. Casting straight with short gives me a value of 0. so what's the solution?

Can anyone tell me how to do this - ideally without loss of precision - or minimal loss of precision if possible?

+3


source to share


4 answers


public static short floatToShort(float x) {
    if (x < Short.MIN_VALUE) {
        return Short.MIN_VALUE;
    }
    if (x > Short.MAX_VALUE) {
        return Short.MAX_VALUE;
    }
    return (short) Math.round(x);
}

      

You will lose the fractional part:

float    4 byte floating-point
double   8 byte floating-point (normal)
short    2 byte integer
int      4 byte integer (normal)
long     8 byte integer

      



Edit:

You may have wanted to know how to store a float bit (4 bytes) to int (4 bytes): ( http://docs.oracle.com/javase/7/docs/api/java/lang/Float.html#floatToRawIntBits ( float) )

float x = 0.1f;
int n = Float.floatToRawIntBits(x);
float y = Float.intBitsToFloat(n);

      

+5


source


Basically, you can just multiply it by 100000, convert it to int and then subtract -32,767 and convert it to short. If that still puts it in the -32,767 to 32,767 range for all your values, that's probably the best you can do. Otherwise, you will have to limit the precision and multiply by 10000.



And when you use, of course, you have to remember to split it.

+6


source


short

is an integral type , so it can only contain integers. The only two options for 0.37885

in short

are 0

or 1

, both of which (I think) lose some precision.

So the answer is: if you lose all fractional values, use the listing Float#shortValue

or Math.round(float)

(and translate the result int

into short

).

Example: Live Copy

float f1 = 0.37885f;
short s1 = (short)Math.round(f1);
System.out.println("s1 = " + s1);

float f2 = 27.67885f;
short s2 = (short)Math.round(f2);
System.out.println("s2 = " + s2);

      

Output:

s1 = 0
s2 = 28

In a comment, you said:

I have this sine wave that generates values ​​like the ones mentioned above, but I want them to be shorts.

Now we can do something about it. Presumably, the values ​​you get are between 0

and 1

. You can store them as shorts by multiplying. Since the range of a short

is -32,768 to 37,767, a convenient number to multiply them might be 10,000:

short s = Math.round(floatValue * 10000);

      

The number we got for your example would be 3789

. Example: Live Copy

float floatValue = 0.37885f;
short s = (short)Math.round((double)floatValue * 10000);
System.out.println("s = " + s);

      

It is not the same value, of course it is a value multiplied by ten thousand, so wherever you intend to use it, you will have to take that into account.

+1


source


If your input values float

are in a specific range (for now, let's say they are in the range -1..1

, exclusive), you can multiply them to get the value you throw away.

Valid short range: -32768..32767

so you can use multiple s 32768

in this case (max short / max input value).

For example:

float f = 0.23451f;
short s = (short) (f * 32768);

      

To decode the value short

to float

:

float f2 = s / 32768f;

      

0


source







All Articles