How to read 2-byte float in Erlang? - erlang

Seems there are a lot of half float questions in other languages, but could not find one for Erlang.
So, I have a 2-byte float as part of a longer binary pattern input. I tried to use pattern matching like <<AFloat:16/float>> and got warning/error in compiler, while using 32/float produced no warning.
Question is: What workaround is there in Erlang to convert the 2-byte binary into float?
I saw the other elaborate bit processing answer to "reading from binary file in Erlang", and do not know if it is required in this case.
* Thanks for the answers below. I shall try them out later *
-- two sets of sample input: EF401C3FEA3F, 1242C341C341

It looks like Erlang does not support float widths other than 32 and 64 (at least currently), but I can't seem to find any documentation that says this explicitly.
Update: I checked the implementation of the bit syntax, and it definitely only handles 32 and 64 bit floats. This should really be better documented.
Update again: added to documentation upstream now.
Final update: Just saw your note about hex input. If you solve that as a first step, transforming the hex string H to a binary B with the actual data bytes, you can use the following to repack the data as 32-bit floats (a simple transformation), and then extract those the normal way:
Floats = [F || <<F:32/float>> <- [<<S:1,(E+(127-15)):8,(M bsl 13):23>> || <<S:1,E:5,M:10>> <- B]]

There is no support for 16 bit floats. If you want collect and works on float coming from another system (via a file for example) then you can easily convert this float to the representation used in your VM.
First read the file and extract the float16 as a 2 bytes binary, and call this conversion function:
-module (float16).
-export([conv_16_to_vm/1]).
% conv_16_to_vm(binary) with binary is a 16 bit float representation
conv_16_to_vm(<<S:1,E:5,M:10>>)->
conv(S,E,M).
conv(_,0,0) -> 0.0;
conv(_,31,_) -> {error,nan_or_qnan_or_infinity};
% Sign management
conv(1,E,M) -> -conv(0,E,M);
% sub normal floats
conv(0,0,M) -> M/(1 bsl 24);
% normal floats
conv(0,E,M) when E < 25 -> (1024 + M)/(1 bsl (25-E));
conv(0,25,M) -> (1024 + M);
conv(0,E,M) -> (1024 + M)*(1 bsl (E-25)).
I used the definition provided by Wikipedia and you can test it:
1> c(float16).
{ok,float16}
2> float16:conv_16_to_vm(<<0,1>>). % 0 00000 0000000001
5.960464477539063e-8
3> float16:conv_16_to_vm(<<3,255>>). % 0 00011 1111111111
6.097555160522461e-5
4> float16:conv_16_to_vm(<<4,0>>). % 0 00100 0000000000
6.103515625e-5
5> float16:conv_16_to_vm(<<123,255>>). % 0 11110 1111111111
65504
6> float16:conv_16_to_vm(<<60,0>>). % 0 01111 0000000000
1.0
7> float16:conv_16_to_vm(<<60,1>>). % 0 01111 0000000001
1.0009765625
8> float16:conv_16_to_vm(<<59,255>>). % 0 01110 1111111111
0.99951171875
8> float16:conv_16_to_vm(<<53,85>>). % 0 01101 0101010101
0.333251953125
As you should expect, the traditional problem or "rounding" is much more visible.

Related

bit32.band like operation in 64 bits

I want to apply a bitwise AND operation in 64 bits in Lua 5.1. Is there an algorithm for it? (I have no idea on how to do it.)
Note: I only need to operate on 48 bits at total, and I am not having trouble with them.
In the game's Lua I'm scripting there's the bit32 library only.
local function band48 (x, y)
local xl = x % 4294967296
local yl = y % 4294967296
local xh = (x - xl) / 4294967296
local yh = (y - yl) / 4294967296
return bit32.band(xh, yh) * 4294967296 + bit32.band(xl, yl)
end
print(band48(7 * 2^33 + 3, 5*2^33 + 5)) --> 5*2^33+1 = 42949672961
Lua is using double floating numbers internally by default. It has only 52 bits for mantissa, so you can't safely store 64-bit integers without risking to get invalid floating point values. With 32 bits it's quite safe. Lua 5.2 manuals describe what happens in bit32 lib with the numbers:
Unless otherwise stated, all functions accept numeric arguments in the
range (-2^51,+2^51); each argument is normalized to the remainder of its
division by 2^32 and truncated to an integer (in some unspecified way),
so that its final value falls in the range [0,2^32 - 1]. Similarly, all
results are in the range [0,2^32 - 1].
You'll have to work in 32-bit chunks.Or maybe introduce your own 64-bits type, probably hosted with userdata, and define 64-bit actions for that type.

Conversion of bitstring to decimal in Erlang

I am trying to decode the bitstring to decimal value. For e.x I have these kind of bitstrings
<<96,64,112,153,9:4>>. I want to convert them to decimal values like you take four bits as a digit (96(01100000) --> 60( first four bits is 6, next four bits is 0) , 64 --> 40 and so on. The output would be 604070999. The last 9:4 represents that you consider 4 bits to represent.
Can anyone help in doing this function erlang.
If you have a binary rather than a bitstring (i.e., without the trailing 9:4 part), you can apply a hex conversion to each byte within a binary comprehension, then convert the resulting binary to an integer:
1> Bin = <<96,64,112,153>>.
<<96,64,112,153>>
2> binary_to_integer(<< <<(integer_to_binary(B,16))/binary>> || <<B:8>> <= Bin >>).
60407099
The same also works for your bitstring, taking 4 bits at a time instead of 8 in the comprehension:
3> Bits = <<96,64,112,153,9:4>>.
<<96,64,112,153,9:4>>
4> binary_to_integer(<< <<(integer_to_binary(B,16))/binary>> || <<B:4>> <= Bits >>).
604070999
But as #Hynek-Pichi-Vychodil points out in the comments, for the bitstring you don't need the integer_to_binary/2 call at all, but instead can convert each 4-bit digit to its corresponding character by adding $0, the literal for the character 0:
5> binary_to_integer(<< <<($0+B)>> || <<B:4>> <= Bits >>).
604070999

How to parse a decimal fraction into Rational in Haskell?

I've been participating in a programming contest and one of the problems' input data included a fractional number in a decimal format: 0.75 is one example.
Parsing that into Double is trivial (I can use read for that), but the loss of precision is painful. One needs to be very careful with Double comparisons (I wasn't), which seems redundant since one has Rational data type in Haskell.
When trying to use that, I've discovered that to read a Rational one has to provide a string in the following format: numerator % denominator, which I, obviously, do not have.
So, the question is:
What is the easiest way to parse a decimal representation of a fraction into Rational?
The number of external dependencies should be taken into consideration too, since I can't install additional libraries into the online judge.
The function you want is Numeric.readFloat:
Numeric Data.Ratio> fst . head $ readFloat "0.75" :: Rational
3 % 4
How about the following (GHCi session):
> :m + Data.Ratio
> approxRational (read "0.1" :: Double) 0.01
1 % 10
Of course you have to pick your epsilon appropriately.
Perhaps you'd get extra points in the contest for implementing it yourself:
import Data.Ratio ( (%) )
readRational :: String -> Rational
readRational input = read intPart % 1 + read fracPart % (10 ^ length fracPart)
where (intPart, fromDot) = span (/='.') input
fracPart = if null fromDot then "0" else tail fromDot

Binary to Integer -> Erlang

I have a binary M such that 34= will always be present and the rest may vary between any number of digits but will always be an integer.
M = [<<"34=21">>]
When I run this command I get an answer like
hd([X || <<"34=", X/binary >> <- M])
Answer -> <<"21">>
How can I get this to be an integer with the most care taken to make it as efficient as possible?
[<<"34=",X/binary>>] = M,
list_to_integer(binary_to_list(X)).
That yields the integer 21
As of R16B, the BIF binary_to_integer/1 can be used:
OTP-10300
Added four new bifs, erlang:binary_to_integer/1,2,
erlang:integer_to_binary/1, erlang:binary_to_float/1 and
erlang:float_to_binary/1,2. These bifs work similarly to how
their list counterparts work, except they operate on
binaries. In most cases converting from and to binaries is
faster than converting from and to lists.
These bifs are auto-imported into erlang source files and can
therefore be used without the erlang prefix.
So that would look like:
[<<"34=",X/binary>>] = M,
binary_to_integer(X).
A string representation of a number can be converted by N-48. For multi-digit numbers you can fold over the binary, multiplying by the power of the position of the digit:
-spec to_int(binary()) -> integer().
to_int(Bin) when is_binary(Bin) ->
to_int(Bin, {size(Bin), 0}).
to_int(_, {0, Acc}) ->
erlang:trunc(Acc);
to_int(<<N/integer, Tail/binary>>, {Pos, Acc}) when N >= 48, N =< 57 ->
to_int(Tail, {Pos-1, Acc + ((N-48) * math:pow(10, Pos-1))}).
The performance of this is around 100 times slower than using the list_to_integer(binary_to_list(X)) option.

integer division

By definition the integer division returns the quotient.
Why 4613.9145 div 100. gives an error ("bad argument") ?
For div the arguments need to be integers. / accepts arbitrary numbers as arguments, especially floats. So for your example, the following would work:
1> 4613.9145 / 100.
46.139145
To contrast the difference, try:
2> 10 / 10.
1.0
3> 10 div 10.
1
Documentation: http://www.erlang.org/doc/reference_manual/expressions.html
Update: Integer division, sometimes denoted \, can be defined as:
a \ b = floor(a / b)
So you'll need a floor function, which isn't in the standard lib.
% intdiv.erl
-module(intdiv).
-export([floor/1, idiv/2]).
floor(X) when X < 0 ->
T = trunc(X),
case X - T == 0 of
true -> T;
false -> T - 1
end;
floor(X) ->
trunc(X) .
idiv(A, B) ->
floor(A / B) .
Usage:
$ erl
...
Eshell V5.7.5 (abort with ^G)
> c(intdiv).
{ok,intdiv}
> intdiv:idiv(4613.9145, 100).
46
Integer division in Erlang, div, is defined to take two integers as input and return an integer. The link you give in an earlier comment, http://mathworld.wolfram.com/IntegerDivision.html, only uses integers in its examples so is not really useful in this discussion. Using trunc and round will allow you use any arguments you wish.
I don't know quite what you mean by "definition." Language designers are free to define operators however they wish. In Erlang, they have defined div to accept only integer arguments.
If it is the design decisions of Erlang's creators that you are interested in knowing, you could email them. Also, if you are curious enough to sift through the (remarkably short) grammar, you can find it here. Best luck!
Not sure what you're looking for, #Bertaud. Regardless of how it's defined elsewhere, Erlang's div only works on integers. You can convert the arguments to integers before calling div:
trunc(4613.9145) div 100.
or you can use / instead of div and convert the quotient to an integer afterward:
trunc(4613.9145 / 100).
And trunc may or may not be what you want- you may want round, or floor or ceiling (which are not defined in Erlang's standard library, but aren't hard to define yourself, as miku did with floor above). That's part of the reason Erlang doesn't assume something and do the conversion for you. But in any case, if you want an integer quotient from two non-integers in Erlang, you have to have some sort of explicit conversion step somewhere.

Resources