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?
source to share
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);
source to share
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.
source to share
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.
source to share
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;
source to share