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

math.big.bitwise_not is wrong #23792

Open
tankf33der opened this issue Feb 23, 2025 · 11 comments
Open

math.big.bitwise_not is wrong #23792

tankf33der opened this issue Feb 23, 2025 · 11 comments
Labels
Bug This tag is applied to issues which reports bugs. Modules: math.big Bugs related to the `math.big` module. Status: Confirmed This bug has been confirmed to be valid by a contributor.

Comments

@tankf33der
Copy link

tankf33der commented Feb 23, 2025

Describe the bug

My test framework against gmp found issue in %subj%.

Please check yourself and fix.

Reproduction Steps

>>> v := 42834833
>>> ~v
-42834834

>>> import math.big
>>> v_a := big.integer_from_string('42834833')!
>>> v_a.str()
42834833
>>> v_b := v_a.bitwise_not()
>>> v_b.str()
4252132462
>>> 

Expected Behavior

math and big.math should return the same numbers on small input.

Current Behavior

please check why vlang returns wrong (?) result against python and ruby too.

Possible Solution

No response

Additional Information/Context

No response

V version

V 0.4.9 5376a55

Environment details (OS name and version, etc.)

|V full version      |V 0.4.9 515d78d.5376a55
|:-------------------|:-------------------
|OS                  |linux, N/A
|Processor           |8 cpus, 64bit, little endian, 11th Gen Intel(R) Core(TM) i5-1135G7 @ 2.40GHz
|Memory              |10.3GB/15.37GB
|                    |
|V executable        |/home/mpech/v/v
|V last modified time|2025-02-23 06:52:56
|                    |
|V home dir          |OK, value: /home/mpech/v
|VMODULES            |OK, value: /home/mpech/.vmodules
|VTMP                |OK, value: /tmp/v_1000
|Current working dir |OK, value: /home/mpech
|                    |
|Git version         |git version 2.47.2
|V git status        |weekly.2025.08-27-g5376a55c
|.git/config present |true
|                    |
|cc version          |cc (Alpine 14.2.0) 14.2.0
|gcc version         |gcc (Alpine 14.2.0) 14.2.0
|clang version       |Alpine clang version 19.1.4
|tcc version         |tcc version 0.9.27 mob:d3e940c (x86_64 Linux)
|tcc git status      |thirdparty-linuxmusl-amd64 a3e24da2
|emcc version        |N/A
|glibc version       |Error: musl libc (x86_64)
Version 1.2.5
Dynamic Program Loader
Usage: /lib/ld-musl-x86_64.so.1 [options] [--] pathname

Note

You can use the 👍 reaction to increase the issue's priority for developers.

Please note that only the 👍 reaction to the issue itself counts as a vote.
Other reactions and those to comments will not be taken into account.

@tankf33der tankf33der added the Bug This tag is applied to issues which reports bugs. label Feb 23, 2025
Copy link

Connected to Huly®: V_0.6-22203

@JalonSolov
Copy link
Contributor

JalonSolov commented Feb 23, 2025

Translating that into a runnable file:

import math.big

v_a := big.integer_from_string('42834833')!
println(v_a.str())

v_b := v_a.bitwise_not()
println(v_b.str())

gives output of

42834833
4252132462

@JalonSolov JalonSolov added the Status: Confirmed This bug has been confirmed to be valid by a contributor. label Feb 23, 2025
@jorgeluismireles
Copy link

Bitwise not changes a bit false into true and vice versa. When you print the numbers as hex seems every bit changes accordingly but I assume a smallest number of bytes is used to store a given big number. If you apply twice the bitwise not you get the same number again:

import math.big

v_a := big.integer_from_string('42834833')!
println(v_a.hex())
v_b := v_a.bitwise_not()
println(v_b.hex())
v_c := v_b.bitwise_not()
println(v_c.hex())
assert v_a == v_c
28d9b91
fd72646e
28d9b91
import math.big

v_a := big.integer_from_string('428348336495867293045968102834596833948576820394959929312048682375978960')!
println(v_a.hex())
v_b := v_a.bitwise_not()
println(v_b.hex())
v_c := v_b.bitwise_not()
println(v_c.hex())
assert v_a == v_c
3e1052a5e204cc56e8f3cef02c2f2ed5c5810b1ef849fbfeaec7e6ea1fd0
ffffc1efad5a1dfb33a9170c310fd3d0d12a3a7ef4e107b6040151381915e02f
3e1052a5e204cc56e8f3cef02c2f2ed5c5810b1ef849fbfeaec7e6ea1fd0

Even though, the bits of a negative number are tricky

import math.big

v_a := big.integer_from_string('-1')!
println(v_a.hex())
v_b := v_a.bitwise_not()
println(v_b.hex())
v_c := v_b.bitwise_not()
println(v_c.hex())
assert v_a == v_c
-1
fffffffe
1
code.v:9:NaN: fn main.main: assert v_a == v_c
  left value: v_a = -1
  right value: v_c = 1
V panic: Assertion failed...

How to know last fffffffe was a -1or a +4294967294?

@spytheman
Copy link
Member

what does gmp do in that case?

@spytheman
Copy link
Member

btw, we have a separate .neg() method:

import math.big

v_a := big.integer_from_string('42834833')!
println(v_a.str())
println(v_a.neg().str())

printing:

42834833
-42834833

@spytheman
Copy link
Member

what are ruby's and python's equivalents?

@tankf33der
Copy link
Author

what does gmp do in that case?

42834833 -> -42834834

@tankf33der
Copy link
Author

what are ruby's and python's equivalents?

python and ruby and bigmath from dlang.

42834833 -> -42834834

@spytheman
Copy link
Member

I should have asked a more detailed question, sorry.

How do you invoke the corresponding operations, using GMP, and in python and ruby?
I do not want just the result, I want programs that I can run and experiment with, and that I can use the source to make comparisons.

@spytheman spytheman added the Modules: math.big Bugs related to the `math.big` module. label Feb 24, 2025
@tankf33der
Copy link
Author

ruby not.rb

v = 42834833
puts ~v

python3 not.py

v = 42834833
print(~v)

ldc2 not.d && not

void main()
{
    import std.bigint;
    import std.stdio: writeln;

    BigInt b = "42834833";
    writeln(~b);
}

go run not.go

package main

import (
        "fmt"
        "math/big"
)

func main() {
        v := big.NewInt(42834833)
        fmt.Println(new(big.Int).Not(v))
}

gcc not.c -lgmp && ./a.out

#include <stdio.h>
#include <gmp.h>

int main() {
    mpz_t v;
    mpz_init(v);

    mpz_set_str(v, "42834833", 10);
    mpz_com(v, v);
    gmp_printf("%Zd\n", v);

    mpz_clear(v);
    return 0;
}

@tankf33der
Copy link
Author

important addition: bitwise_or, bitwise_and and bitwise_xor tested against gmp and different range numbers (up to 30k digits) and a large number of launches (1M).

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Bug This tag is applied to issues which reports bugs. Modules: math.big Bugs related to the `math.big` module. Status: Confirmed This bug has been confirmed to be valid by a contributor.
Projects
None yet
Development

No branches or pull requests

4 participants