Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add bitwise AND, OR and XOR modes to math block #91

Open
wants to merge 6 commits into
base: master
Choose a base branch
from

Conversation

dominik-korsa
Copy link

@dominik-korsa dominik-korsa commented Sep 30, 2024

This PR implements the bitwise AND, bitwise OR and bitwise XOR math block modes from #90.

I've decided not to implement the bitwise NOT operation, as it would require establishing the number of bits in the integer (if Lua used 32-bit or 64-bit integers it would be simple, but it uses doubles instead). The bitwise not operation is equivalent to a bitwise XOR with a number consisting of only binary ones.

The current behaviour for numbers that are not non-negative integers is:

  • negative numbers are treated as 0
  • non-integers are rounded to the nearest integer (0.1 is treated as 0, 0.5 and 0.9 are treated as 1)

Maybe the behaviour should be different? Should a math.floor operation be used instead of math.round?

image
image
image
image

@JuneCarya
Copy link

JuneCarya commented Sep 30, 2024

Not sure whether this might be relevant, but maybe you might want to have a look into the bit operations library of LuaJIT https://bitop.luajit.org/ and see whether this could be applicable to your implementation.

@dominik-korsa
Copy link
Author

dominik-korsa commented Sep 30, 2024

Not sure whether this might be relevant, but maybe you might want to have a look into the bit operations library of LuaJIT https://bitop.luajit.org/ and see whether this could be applicable to your implementation.

I can't seem to find the source code for that library (and even if I were able to do so, it's unlikely the C++ implementation would be applicable to my Lua implementation). What's interesting is the page describing the semantics of BitOp. They've decided to only support arithmetic in the range of signed int32 (-31^2 to +31^2-1 inclusive). For Scrap Mechanic where the number type is always a double, integers up to 2^52 could be supported. In BitOp the behaviour for non-integers is implementation-defined and should not be relied upon.

Setting a maximum range would allow to implement the bitwise not operation and bitwise operations on negative integers, but would make the implementation trickier and would require deciding on the behaviour for numbers above 2^52.

@JuneCarya
Copy link

If I'm not mistaken the bitwise operation library is exposed to the environment within the table bit.
You should be able to access all bitwise operations with bit.*.

I'm not exactly sure if the SM devs ended up using a different bitwise operations library or the one shipped with LuaJIT.
I suppose you'd have to check what the results of the library's functions are.

@dominik-korsa
Copy link
Author

If I'm not mistaken the bitwise operation library is exposed to the environment within the table bit. You should be able to access all bitwise operations with bit.*.

I'm not exactly sure if the SM devs ended up using a different bitwise operations library or the one shipped with LuaJIT. I suppose you'd have to check what the results of the library's functions are.

Hey, thanks for this suggestion. The latest commits change the implementation to use the bit.* namespace

Comment on lines 17 to 44
-- parses user-provided number strings
-- - removes all spaces
-- - parses binary numbers with the "0b", "0B" prefixes or "b" suffix
-- - parses hexadecimal numbers with the "0x", "0X" prefixes
-- returns nil for incorrectly formatted strings
--
-- Examples:
-- math.parsestring(" 1 000 000 ") == 1000000
-- math.parsestring("0xFF") == 255
-- math.parsestring("0b1000") == 8
-- math.parsestring("1000b") == 8
-- math.parsestring("test") == nil
function math.parsenumber(input)
normalized = string.gsub(input, "%s+", "") -- remove spaces:

prefix = string.sub(normalized, 1, 2)
suffix = string.sub(normalized, -1, -1)
if suffix == "b" or suffix == "B" then
return tonumber(string.sub(normalized, 1, -2), 2)
elseif prefix == "0b" or prefix == "0B" then
return tonumber(string.sub(normalized, 3, -1), 2)
elseif prefix == "0x" or prefix == "0X" then
return tonumber(string.sub(normalized, 3, -1), 16)
else
return tonumber(normalized, 10)
end
end

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think it's best to move this function outside of the math namespace, as it's shared with all mod/vanilla scripts. I know we've done it with more functions, but this could interfere with other mods that define a function with the same name.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Right, I've moved math.parsenumber to a new lib input (maybe there is a clearly better place to put it?) as mp_parseNumber

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants