bit32.band like operation in 64 bits - lua

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.

Related

LUA 5.4 - How to convert 64-bit numbers to hex

I wanted to convert numbers greater than 64 bits, including up to 256 bits number from decimal to hex in lua.
Example:
num = 9223372036854775807
num = string.format("%x", num)
num = tostring(num)
print(num) -- output is 7fffffffffffffff
but if I already add a single number, it returns an error in the example below:
num = 9223372036854775808
num = string.format("%x", num)
num = tostring(num)
print(num) -- error lua54 - bad argument #2 to 'format' (number has no integer representation)
Does anyone have any ideas?
I wanted to convert numbers greater than 64 bits, including up to 256 bits number from decimal to hex in lua.
Well that's not possible without involving a big integer library such as this one. Lua 5.4 has two number types: 64-bit signed integers and 64-bit floats, which are both to limited to store arbitrary 256-bit integers.
The first num in your example, 9223372036854775807, is just the upper limit of int64 bounds (-2^63 to 2^63-1, both inclusive). Adding 1 to this forces Lua to cast it into a float64, which can represent numbers way larger than that at the cost of precision. You're then left with an imprecise float which has no "integer representation" as Lua tells you.
You could trivially reimplement %x yourself, but that wouldn't help you extend the precision/size of floats & ints. You need to find another number representation and find or write a bigint library to go with it. Options are:
String representation: Represent numbers as hex- or bytestrings (base 256).
Table representation: Represent numbers as lists of numbers (base 2^x where x is < 64)

How to read 2-byte float in 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.

Dart: split an arbitrarily precised number onto a sequence of bytes

Assuming I have a declaration like this: final int input = 0xA55AA9D2;, I'd like to get a list of [0xA5, 0x5A, 0xA9, 0xD2]. It is easily achievable in Java by just right shifting the input by 24, 16, 8 and 0 respectively with subsequent cast to byte in order to cut precision to 8-bit value.
But how to do the same with Dart? I can't find sufficient information about numbers encoding (e.g. in Java front 1 means minus, but how is minus encoded here?) and transformations (e.g. how to cut precision) in order to solve this task.
P.S.: I solved this for 32-bit numbers using out.add([value >> 24, (value & 0x00FFFFFF) >> 16, (value & 0x0000FFFF) >> 8, value & 0X000000FF]); but it feels incredibly ugly, I feel that SDK provides more convenient means to split an arbitrarily precised number into bytes
The biggest issue here is that a Dart int is not the same type on the VM and in a browser.
On the native VM, an int is a 64-bit two's complement number.
In a browser, when compiled to JavaScript, an int is just a non-fractional double because JavaScript only has doubles as numbers.
If your code is only running on the VM, then getting the bytes is as simple as:
int number;
List<int> bytes = List.generate(8, (n) => (number >> (8 * n)) & 0xFF);
In JavaScript, bitwise operations only work on 32-bit integers, so you could do:
List<int> bytes = List.generate(4, (n) => (number >> (8 * n)) & 0xFF);
and get the byte representation of number.toSigned(32).
If you want a number larger than that, I'd probably use BigInt:
var bigNumber = BigInt.from(number).toSigned(64);
var b255 = BigInt.from(255);
List<int> bytes = List.generate(8, (n) => ((bigNumber >> (8 * n)) & b255).toInt());
From the documentation to the int class:
The default implementation of int is 64-bit two's complement integers with operations that wrap to that range on overflow.
Note: When compiling to JavaScript, integers are restricted to values that can be represented exactly by double-precision floating point values. The available integer values include all integers between -2^53 and 2^53 ...
(Most modern systems use two's complement for signed integers.)
If you need your Dart code to work portably for both web and for VMs, you can use package:fixnum to use fixed-width 32- or 64-bit integers.

How to shift and mask bits from integer in Lua?

I'm porting an Objective-C iOS application to CoronaSDK which uses Lua. I have a signed 16-bit integer and I want to isolate the high and low bytes in it. In C you can simply do:
uint8_t a = (dx >> 8) & 0xff;
uint8_t b = dx & 0xff;
Lua has no bitwise operators. How can I do this in Lua? This is for a mobile application and external binary libraries to extend Lua would most likely not work in all devices, if any. Any pure Lua solutions to this problem that you could suggest?
I don't know Lua but can give you a general idea. Right shift by n is equivalent to divide by 2^n. You can first divide by 2^8 = 256 to get the MSBs and then multiply and divide by 2^8 to get LSBs.
MSBs = dx / 256
LSBleftsifted = (ds * 256)
LSBs = LSBleftsifted / 256
This is considering that all this is an unsigned integer operation.
Based on #ash answer, here are a couple of Lua functions. I'm sure they can be generalized, but this does what I needed:
local function getLowByte16( value )
local high_value = math.floor(value/256)
high_value = high_value*256
local low_value = value - high_value
return low_value
end
local function getHighByte16( value )
local high_value = math.floor(value/256)
return high_value
end

Lua: converting from float to int

Even though Lua does not differentiate between floating point numbers and integers, there are some cases when you want to use integers. What is the best way to covert a number to an integer if you cannot do a C-like cast or without something like Python's int?
For example when calculating an index for an array in
idx = position / width
how can you ensure idx is a valid array index? I have come up with a solution that uses string.find, but maybe there is a method that uses arithmetic that would obviously be much faster. My solution:
function toint(n)
local s = tostring(n)
local i, j = s:find('%.')
if i then
return tonumber(s:sub(1, i-1))
else
return n
end
end
You could use math.floor(x)
From the Lua Reference Manual:
Returns the largest integer smaller than or equal to x.
Lua 5.3 introduced a new operator, called floor division and denoted by //
Example below:
Lua 5.3.1 Copyright (C) 1994-2015 Lua.org, PUC-Rio
>12//5
2
More info can be found in the lua manual
#Hofstad is correct with the math.floor(Number x) suggestion to eliminate the bits right of the decimal, you might want to round instead. There is no math.round, but it is as simple as math.floor(x + 0.5). The reason you want to round is because floats are usually approximate. For example, 1 could be 0.999999996
12.4 + 0.5 = 12.9, floored 12
12.5 + 0.5 = 13, floored 13
12.6 + 0.5 = 13.1, floored 13
local round = function(a, prec)
return math.floor(a + 0.5*prec) -- where prec is 10^n, starting at 0
end
why not just use math.floor()? it would make the indices valid so long as the numerator and denominator are non-negative and in valid ranges.

Resources