-
Notifications
You must be signed in to change notification settings - Fork 78
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_rem
test fails on the i686 target
#243
Comments
Backtrace after recompiling tests in debug:
|
Looks like this test Lines 134 to 138 in 1ac39f8
|
I also suspected that, but 4000000001 should fit in 32 bits just fine, and the previous tests also deal with this value without failure; so it seems this is about the logic behind div-by-zero error catching? |
jaq seems to use |
Ah, you're right, I didn't take signed integer into account. I patched the numbers to make them much smaller in that test and now it succeeds, but it makes me worry that the other tests with that value are only passing by accident... |
@tranzystorekk, I would be happy to accept a PR from you with the smaller numbers. |
I'm wondering if switching the int repr in jaq-json to |
Reduces large isize to remain below maximum for signed 32 bit int, resolves 01mf02#243
It fails on |
@GaetanLepage does a smaller number work? could try #245 |
Well, after more testing, I found out that the problematic line was |
Oh ok, what does |
|
Whereas it is
on |
Huh, is this macOS or some other darwin based os? @01mf02 any idea what is going on? known float behaviour? |
MacOS, running on an |
I'm sorry, I have no idea what is happening here. If it helps, the documentation for what should happen is here: https://doc.rust-lang.org/std/primitive.f64.html#impl-Rem-for-f64. Perhaps, @GaetanLepage, could you tell us what |
Hmm confusing, i got i M3 macbook so i guess i could install rosetta somehow. I wonder what other language implementation does, could you try this with rosetta?
|
In the meantime, our darwin builder got updated to an M4 machine.
and
|
Tried to expand and translate the jq code into what it will end up in rust:
But seems i'm missing something: $ rustc -o test <(echo 'fn main() { dbg!(f64::total_cmp(&(2.1 % 0.0), &(0.0 / 0.0))); }') && ./test
[/dev/fd/11:1:13] f64::total_cmp(&(2.1 % 0.0), &(0.0 / 0.0)) = Equal
$ rustc --target x86_64-apple-darwin -o test <(echo 'fn main() { dbg!(f64::total_cmp(&(2.1 % 0.0), &(0.0 / 0.0))); }') && ./test
[/dev/fd/11:1:13] f64::total_cmp(&(2.1 % 0.0), &(0.0 / 0.0)) = Equal |
@wader, this @GaetanLepage: Can you post the output of |
This gives me |
Dugg a bit more With this fn float_cmp(left: f64, right: f64) -> Ordering {
if left == 0. && right == 0. {
Ordering::Equal
} else {
let lb = left.to_bits() as i64;
let rb = right.to_bits() as i64;
dbg!(&left, &right);
dbg!(lb, rb);
f64::total_cmp(&left, &right)
}
} I get this: $cargo run --target x86_64-apple-darwin -- -n '0.0/0.0 == 0.0%0.0'
[jaq-json/src/lib.rs:892:9] &left = NaN
[jaq-json/src/lib.rs:892:9] &right = NaN
[jaq-json/src/lib.rs:893:9] lb = -2251799813685248 # NOTE: on aarch64 this is same value as below
[jaq-json/src/lib.rs:894:9] rb = 9221120237041090560
false So i wonder if one of the NaN-values gets "normalized" etc? ex the NaN payload/flags gets zeroed or something? Still can't reproduce with same-ish code as simple rust code. |
- bump from 1.6.0 to 2.0.1 - remove cargo patch - add patch for tests on 32bit architecture, see: 01mf02/jaq#243 - package MIT license
@wader, thanks for digging! Taking on your approach, may I ask you, @GaetanLepage, to post the output of the following?
I hope that this will yield different outputs for different architectures ... that would explain jaq's behaviour, and we could file an issue at rust-lang. |
One thought that struck me: could compiling a simple program with rustc and building via cargo differ some way that changes float behaviour? some jaq crates dependency pokes at something? different compile optimization levels? |
On all architectures, I get:
|
More digging The two different NaNs as u64 are these:
If one inspect them using my favorite website they are: Update: seems float.exposed it buggy, for 18444492273895866368 one have to provide it in the "Raw Decimal Integer Value" input field. I don't really follow where and how in the jaq code we end up with a signed NaN but f64::total_cmp will see them as no equal so maybe a solution to this and possible other NaN-differences is to do: fn float_cmp(left: f64, right: f64) -> Ordering {
if (left == 0. && right == 0.) || (left.is_nan() && right.is_nan()) {
Ordering::Equal
} else {
f64::total_cmp(&left, &right)
}
} Are the more places to look for this? and it is ok to normalize NaN values like this? maybe only consider signness difference equal? |
I am not aware of such behaviour. On the other hand, for integers, I know that compiling with |
It may be OK to normalize NaN values like this, but first, I would like to understand what is going on here. I'd really like to reproduce the platform-specific difference without jaq-related code. |
Let's get the big cannon out. Can you post the output of the following program? fn main() {
let t: f64 = "2".parse().unwrap();
let z: f64 = "0".parse().unwrap();
let vals = [t / z, z / z, t % z, z % z];
for v in vals {
println!("{v} (bytes = {})", v.to_bits());
}
for v1 in &vals {
for v2 in &vals {
print!("{:?}\t", v1.total_cmp(v2));
}
println!();
}
} On my computer, this yields:
|
On macbook M3
(not exactly sure how x86_64 gets executed on arm but i guess it's transparent thru rosetta, i get same result if do |
@wader: YES! I think we've got it. Just to be sure, can you check one last thing, namely whether replacing |
You mean like this? let t: f64 = 2.0;
let z: f64 = 0.0; hmm then i get:
Now i'm confused. After some poking around it seems this is what differs:
but i don't see any difference in float etc:
Hmm is this the compiler doing some transformations etc? |
@wader, great! So parsing seems to have an impact here. I opened a bug report on rust-lang. Let's see what people have to say there. |
The aarch64 and x86-64 CPUs use different NaNs. |
This is hidden from you by LLVM doing constant propagation, as LLVM normalizes to a particular NaN, irrespective of architecture, if you use the literal float. Otherwise, it is not. |
I think this was misdiagnosed/mis-minimized, and the actual bug here is that jaq is using I don't know what your floating point comparison semantics are supposed to be, but I think you want all NaNs to compare less than all NaNs, or something like that. |
It seems you attempted to use fn float_cmp(left: f64, right: f64) -> Ordering {
match (left.partial_cmp(&right), left.is_nan(), right.is_nan()) {
(None, true, true) => Ordering::Equal,
(None, false, true) => todo!(),
(None, true, false) => todo!(),
(Some(v), false, false) => v,
}
} |
This is actually what happens in jq. I have just made a PR (#248) that proposes to adopt this behaviour after all. |
@workingjubilee, thanks for your suggestion, that's what I settled on in the end. |
When testing jaq 2.0.0 for Void Linux, the test run fails on the i686 platform: https://github.com/void-linux/void-packages/actions/runs/12129949574/job/33819327834?pr=50494
The text was updated successfully, but these errors were encountered: