Fork me on GitHub
#clojure-dev
<
2021-12-04
>
quoll01:12:24

Can I confirm this with others please?

> (doseq [x (range -1073742011 -2147484000 -110)] (when (= 1 (Math/floorMod 1 x)) (println x)))
-2147483691
-2147483801
-2147483911
nil
> (doseq [x (range -2147482742  -2147484000 -110)] (when (= 1 (Math/floorMod 1 x)) (println x)))
-2147483732
-2147483842
-2147483952
nil

quoll02:12:14

The floorMod function is being called with 1 and a large negative number. It should return another large negative number, but occasionally returns 1. It is highly intermittent

quoll02:12:01

If the first argument is -1 instead, then it should be returning -1 every time, but occasionally returns a large positive number instead.

quoll02:12:38

The doseq expressions that I posted should not print anything at all

Alex Miller (Clojure team)02:12:12

Sounds pretty weird. Which jdk?

phronmophobic02:12:24

I was also able to reproduce on: • mac, java 17, aarch64 • mac, java 1.8.0_192, x86_64 (rosetta)

Alex Miller (Clojure team)02:12:03

Well, I've learned these things are usually not the jvm, and that seems like a wide range

Alex Miller (Clojure team)02:12:43

I don't suppose you're running on Rosetta or anything

Alex Miller (Clojure team)02:12:47

I wonder if it's weirdness related to the ulp bounds and then overflow

Alex Miller (Clojure team)02:12:06

Does it happen with StrictMath?

favila02:12:30

This doesn’t happen if I type-hint the x

favila02:12:58

(It’s also way faster)

favila02:12:35

I wonder if it’s sometimes picking the Math.floormod(int int) method incorrectly with a long and the truncation got you

favila02:12:42

(Math/floorMod 1 (unchecked-int -2147483691))
=> 1

favila02:12:59

(time (doseq [x (range -1073742011 -2147484000 -110)] (when (= 1 (Math/floorMod 1 x)) (println x))))
-2147483691
-2147483801
-2147483911
"Elapsed time: 31599.733207 msecs"

favila02:12:17

(time (doseq [x (range -1073742011 -2147484000 -110)] (when (= 1 (Math/floorMod 1 ^long x)) (println x))))
"Elapsed time: 148.864987 msecs"
=> nil

quoll03:12:56

I’m not surprised that the type hinting is faster. And yes, I think it’s just a case of selecting the wrong function and getting an argument truncated.

quoll03:12:56

It’s not just the second argument. When I gave it a type, and tried it in generative tests again, it failed when it truncated the first argument. I can only avoid the problem when both arguments have explicit types

favila06:12:52

There’s a patch there

mikerod15:12:01

Wow CLJ-2413 I'd think would be the case with different runs of the VM. However the non-determinism happening within a single instance is really surprising if that's the case

seancorfield21:12:37

Does Clojure support calling methods on static inner classes? A question came up in #java and I can repro the problem: can call .toString() overridden from Object but can't any of the methods declared in that inner static class...

Alex Miller (Clojure team)22:12:01

As a general matter, yes, but the privacy levels depend of course

borkdude22:12:23

$ cat Foo.java
public class Foo {

    public static class Bar {
        public Bar () {

        }
        public void doSomething() {
            System.out.println("hello");
        }
    }
}
$ javac Foo.java
$ clj -Sdeps '{:paths ["."]}'
Clojure 1.11.0-alpha3
user=> (new Foo$Bar)
#object[Foo$Bar 0x54dcbb9f "Foo$Bar@54dcbb9f"]
user=> (.doSomething (new Foo$Bar))
hello
nil
user=>

seancorfield22:12:43

Thanks for the extra set of eyes @alexmiller -- I'd missed it was a private inner class 😞