digitalmars.D - maybe a floating point issue?
- czylabsonasa (93/93) Sep 18 Hi.
- Serg Gini (6/11) Sep 19 In D code you allocating p vector of size A+C
- czylabsonasa (8/21) Sep 19 Thanks, Serg, good catch, usually i set the limits a little bit
- czylabsonasa (40/40) Sep 19 ... and even the following `julia` code is OK:
- Serg Gini (5/9) Sep 19 And you said you made some random tests - and results are the
- czylabsonasa (7/11) Sep 19 Yes, i tested the C++ and D code with a thousand (literally) of
- Denis Feklushkin (2/9) Sep 19 ```
- czylabsonasa (8/20) Sep 19 Denis, the kattis site probably using linux+gdc-14, and i tested
- Dennis (30/34) Sep 19 One difference between the C++ and D code is that your D code
- czylabsonasa (5/41) Sep 19 Denis, thanks for your time, but if there would such an input
- matheus (4/7) Sep 19 Hi, have you tried checking the Assembly code between both
- czylabsonasa (2/5) Sep 19 Matheus, i'm using programming langs as a black box :-), i know
- Timon Gehr (43/153) Sep 19 FWIW: if we improve the ability of the optimizer to do alias analysis,
- czylabsonasa (7/9) Sep 19 Timon, good finding! Then, with D, on the kattis site we should
- Sergey (7/17) Sep 19 Maybe we should submit a ticket with request to change the
Hi. I'm trying to solve a programming contest [problem](https://open.kattis.com/problems/anthony) in D. The almost identical solution in C++ got accepted, but I'm unable to find the issue in the D code... Maybe some D expert catch some trivial error in my code? Here is the D source: ```d // Anthony_and_Cora_anthony import std; alias i32=int; alias i64=long; alias f64=double; alias f128=real; alias fT=f64; void main(){ i32 A,C; readf("%d %d\n",A,C); auto p=new fT[](A+C); for(i32 i=1;i<=A+C-1;i++){ readf("%f\n",p[i]); } auto win=new fT[][](A+1,C+1); for(i32 i=0;i<=A;i++){ for(i32 j=0;j<=C;j++){ win[i][j]=-1.0; } } for(i32 i=1;i<=A;i++){ win[i][0]=1.0; } for(i32 j=0;j<=C;j++){ // j=0 ? win[0][j]=0.0; } void Trav(i32 a,i32 c,i32 k){ if(win[a][c]<-0.5){ Trav(a-1,c,k+1); Trav(a,c-1,k+1); win[a][c]=p[k]*win[a][c-1]+(1-p[k])*win[a-1][c]; } } Trav(A,C,1); writef("%.7f\n",win[A][C]); } ``` The approach is a top-down one with memoization. Tried both double and real, with no success. What is "surprising" the following C++ code is accepted by the judge system: ```c++ // Anthony_and_Cora_anthony #include <bits/stdc++.h> using namespace std; using i32=int; using f64=double; using f128=long double; using fT=f64; vector<vector<fT>> win; vector<fT> p; void Trav(i32 a,i32 c,i32 k){ if(win[a][c]<-0.5){ Trav(a-1,c,k+1); Trav(a,c-1,k+1); win[a][c]=p[k]*win[a][c-1]+(1-p[k])*win[a-1][c]; } } int main(){ i32 A,C; cin>>A>>C; p.resize(A+C+1); for(i32 i=1;i<=A+C-1;i++){ cin>>p[i]; } win.resize(A+1); for(i32 i=0;i<=A;i++){ win[i].resize(C+1); } for(i32 i=0;i<=A;i++){ for(i32 j=0;j<=C;j++){ win[i][j]=-1.0; } } for(i32 i=1;i<=A;i++){ win[i][0]=1.0; } for(i32 j=0;j<=C;j++){ win[0][j]=0.0; } Trav(A,C,1); cout<<setprecision(7)<<fixed<<win[A][C]<<'\n'; } ``` The D code was tested against the C++ code w/ randomly generated cases, using dmd,ldc2 and gdc-12 compilers, but even `diff` did not give any difference... cheers.
Sep 18
On Friday, 19 September 2025 at 06:23:02 UTC, czylabsonasa wrote:Hi. I'm trying to solve a programming contest [problem](https://open.kattis.com/problems/anthony) in D. TheLet's see:auto p=new fT[](A+C);In D code you allocating p vector of size A+Cp.resize(A+C+1);In C++ code you are allocating p vector of size A+C+1 Maybe on some corner cases of the logic Trav function it can affect the result
Sep 19
On Friday, 19 September 2025 at 07:04:16 UTC, Serg Gini wrote:On Friday, 19 September 2025 at 06:23:02 UTC, czylabsonasa wrote:Thanks, Serg, good catch, usually i set the limits a little bit larger than the requirements, but this time i missed for the D code. To be sure (the devil isn't sleeping...) tried w/ `A+C+1` sized allocation for the D, but no success, and `A+C` sized for the C++ - still accepted. (only the 1,...,A+C-1 indices are accessed). cheersHi. I'm trying to solve a programming contest [problem](https://open.kattis.com/problems/anthony) in D. TheLet's see:auto p=new fT[](A+C);In D code you allocating p vector of size A+Cp.resize(A+C+1);In C++ code you are allocating p vector of size A+C+1 Maybe on some corner cases of the logic Trav function it can affect the result
Sep 19
... and even the following `julia` code is OK: ```jl const _DBG_=false fT=Float64 function solveIt() rL()=readline() rT(S,T=Int)=parse(T,S) A,C=rT.(rL()|>split) p=fill(fT(0.0),A+C-1) for i in 1:A+C-1 p[i]=rT(rL(),fT) end for i in 1:A win[1+i,1+0]=1.0 end for j in 0:C win[1+0,1+j]=0.0 end function Trav(a,c,k) if win[1+a,1+c]<-0.5 Trav(a-1,c,k+1) Trav(a,c-1,k+1) win[1+a,1+c]=p[k]*win[1+a,1+c-1]+(1-p[k])*win[1+a-1,1+c] end end Trav(A,C,1) println(round(win[1+A,1+C];digits=7)) end solveIt() ``` (sorry, but no syntax highlighting here for julia) As i see, the kattis site is using the `-O2` switch for compiling the source, as usual. In the old times - 10 years ago - i experienced striking differences w/ gcc/g++ w/ floating point computations depending on optimization is enabled or not. Because eventually the 3 codes are the same, i am supposing that this the root cause of the issue.
Sep 19
On Friday, 19 September 2025 at 08:31:07 UTC, czylabsonasa wrote:... and even the following `julia` code is OK: floating point computations depending on optimization is enabled or not. Because eventually the 3 codes are the same, i am supposing that this the root cause of the issue.And you said you made some random tests - and results are the same? even for 7 digits precision? It's weird
Sep 19
And you said you made some random tests - and results are the same? even for 7 digits precision? It's weirdYes, i tested the C++ and D code with a thousand (literally) of random instances and got no difference, even comparing the outputs as strings. (For compiling g++ -O2 and gdc-12 -O2 were used in accordance with the kattis site). On my system (lmde/faye) only gdc-12 is available, and i don't want to "mess" it with a different compiler.
Sep 19
On Friday, 19 September 2025 at 06:23:02```d // Anthony_and_Cora_anthony import std; alias i32=int; alias i64=long; alias f64=double; alias f128=real; // may be is not same as long double in C++```
Sep 19
On Friday, 19 September 2025 at 10:06:05 UTC, Denis Feklushkin wrote:On Friday, 19 September 2025 at 06:23:02Denis, the kattis site probably using linux+gdc-14, and i tested my linux+gdc-12 compiled code gives ca. 2^(-16445) for the smallest pos. real, which shows that it is not double, at least on my platform. But i got accepted using double with C++ and Float64 with julia, so the issue is hiding is somewhere else.```d // Anthony_and_Cora_anthony import std; alias i32=int; alias i64=long; alias f64=double; alias f128=real; // may be is not same as long double in C++```
Sep 19
On Friday, 19 September 2025 at 06:23:02 UTC, czylabsonasa wrote:I'm trying to solve a programming contest [problem](https://open.kattis.com/problems/anthony) in D. The almost identical solution in C++ got accepted, but I'm unable to find the issue in the D code...One difference between the C++ and D code is that your D code expects each line to end with a newline character: ```D for(i32 i=1;i<=A+C-1;i++){ readf("%f\n",p[i]); } ``` So if your input file is this: ``` 1 1 0.500000 ``` Your C++ and D programs both output 0.500000. But if your input file lacks the final empty line: ``` 1 1 0.500000 ``` The C++ version still works, but D throws an exception: ``` std/format/spec.d(569): parseToFormatSpec: Cannot find character ' ' in the input string. ``` Perhaps change the D code to this: ```D for(i32 i=1;i<=A+C-1;i++){ p[i] = readln().to!float; } ```
Sep 19
On Friday, 19 September 2025 at 10:25:37 UTC, Dennis wrote:On Friday, 19 September 2025 at 06:23:02 UTC, czylabsonasa wrote:Denis, thanks for your time, but if there would such an input file, then it would resulted in runtime error. Anyway, i tested with readf(" %d %d",...)+read(" %f",...) and no change it is wrong answer.I'm trying to solve a programming contest [problem](https://open.kattis.com/problems/anthony) in D. The almost identical solution in C++ got accepted, but I'm unable to find the issue in the D code...One difference between the C++ and D code is that your D code expects each line to end with a newline character: ```D for(i32 i=1;i<=A+C-1;i++){ readf("%f\n",p[i]); } ``` So if your input file is this: ``` 1 1 0.500000 ``` Your C++ and D programs both output 0.500000. But if your input file lacks the final empty line: ``` 1 1 0.500000 ``` The C++ version still works, but D throws an exception: ``` std/format/spec.d(569): parseToFormatSpec: Cannot find character ' ' in the input string. ``` Perhaps change the D code to this: ```D for(i32 i=1;i<=A+C-1;i++){ p[i] = readln().to!float; } ```
Sep 19
On Friday, 19 September 2025 at 06:23:02 UTC, czylabsonasa wrote:Hi. I'm trying to solve a programming contest [problem](https://open.kattis.com/problems/anthony) in D...Hi, have you tried checking the Assembly code between both version with godbolt.org ? Matheus.
Sep 19
Hi, have you tried checking the Assembly code between both version with godbolt.org ? Matheus.Matheus, i'm using programming langs as a black box :-), i know almost nothing about assembly, but thanks for the suggestion!
Sep 19
On 9/19/25 08:23, czylabsonasa wrote:Hi. I'm trying to solve a programming contest [problem](https:// open.kattis.com/problems/anthony) in D. The almost identical solution in C++ got accepted, but I'm unable to find the issue in the D code... Maybe some D expert catch some trivial error in my code? Here is the D source: ```d // Anthony_and_Cora_anthony import std; alias i32=int; alias i64=long; alias f64=double; alias f128=real; alias fT=f64; void main(){ i32 A,C; readf("%d %d\n",A,C); auto p=new fT[](A+C); for(i32 i=1;i<=A+C-1;i++){ readf("%f\n",p[i]); } auto win=new fT[][](A+1,C+1); for(i32 i=0;i<=A;i++){ for(i32 j=0;j<=C;j++){ win[i][j]=-1.0; } } for(i32 i=1;i<=A;i++){ win[i][0]=1.0; } for(i32 j=0;j<=C;j++){ // j=0 ? win[0][j]=0.0; } void Trav(i32 a,i32 c,i32 k){ if(win[a][c]<-0.5){ Trav(a-1,c,k+1); Trav(a,c-1,k+1); win[a][c]=p[k]*win[a][c-1]+(1-p[k])*win[a-1][c]; } } Trav(A,C,1); writef("%.7f\n",win[A][C]); } ``` The approach is a top-down one with memoization. Tried both double and real, with no success. What is "surprising" the following C++ code is accepted by the judge system: ```c++ // Anthony_and_Cora_anthony #include <bits/stdc++.h> using namespace std; using i32=int; using f64=double; using f128=long double; using fT=f64; vector<vector<fT>> win; vector<fT> p; void Trav(i32 a,i32 c,i32 k){ if(win[a][c]<-0.5){ Trav(a-1,c,k+1); Trav(a,c-1,k+1); win[a][c]=p[k]*win[a][c-1]+(1-p[k])*win[a-1][c]; } } int main(){ i32 A,C; cin>>A>>C; p.resize(A+C+1); for(i32 i=1;i<=A+C-1;i++){ cin>>p[i]; } win.resize(A+1); for(i32 i=0;i<=A;i++){ win[i].resize(C+1); } for(i32 i=0;i<=A;i++){ for(i32 j=0;j<=C;j++){ win[i][j]=-1.0; } } for(i32 i=1;i<=A;i++){ win[i][0]=1.0; } for(i32 j=0;j<=C;j++){ win[0][j]=0.0; } Trav(A,C,1); cout<<setprecision(7)<<fixed<<win[A][C]<<'\n'; } ``` The D code was tested against the C++ code w/ randomly generated cases, using dmd,ldc2 and gdc-12 compilers, but even `diff` did not give any difference... cheers.FWIW: if we improve the ability of the optimizer to do alias analysis, it passes: ```d import std; alias i32=int; alias i64=long; alias f64=double; alias f128=real; alias fT=f64; void main(){ i32 A,C; readf("%d %d\n",A,C); auto p=new fT[](A+C); for(i32 i=1;i<=A+C-1;i++){ readf("%f\n",p[i]); } const i32 stride=C+1; auto win=new fT[]((A+1)*(C+1)); for(i32 i=0;i<=A;i++){ for(i32 j=0;j<=C;j++){ win[i*stride+j]=-1.0; } } for(i32 i=1;i<=A;i++){ win[i*stride+0]=1.0; } for(i32 j=0;j<=C;j++){ win[0*stride+j]=0.0; } void Trav(i32 a,i32 c,i32 k){< const idx=a*stride+c; if(win[idx]<-0.5){ Trav(a-1,c,k+1); Trav(a,c-1,k+1); win[idx]=p[k]*win[a*stride+(c-1)]+(1-p[k])*win[(a-1)*stride+c]; } } Trav(A,C,1); writef("%.7f\n",win[A*stride+C]); } ``` Not sure why this happens with GDC on -O2, I think LDC would refrain from changing results by default.
Sep 19
Not sure why this happens with GDC on -O2, I think LDC would refrain from changing results by default.Timon, good finding! Then, with D, on the kattis site we should begin with the second step :-) I'm not happy about it, bcos there are plenty of interesting geometry/probability tasks on that site, where floating point numbers and (naturally) higher dim. arrays involved, instead of focusing the problem, we must fight with language/compiler.
Sep 19
On Friday, 19 September 2025 at 20:33:31 UTC, czylabsonasa wrote:Maybe we should submit a ticket with request to change the compiler to ldc? I saw they are using many GNU languages (C,C++,Fortran,Modula-2). But they also have LLVM langs (Rust, Crystal). So it should not be a huge problem to install LDC instead of GDC in their environment.Not sure why this happens with GDC on -O2, I think LDC would refrain from changing results by default.Timon, good finding! Then, with D, on the kattis site we should begin with the second step :-) I'm not happy about it, bcos there are plenty of interesting geometry/probability tasks on that site, where floating point numbers and (naturally) higher dim. arrays involved, instead of focusing the problem, we must fight with language/compiler.
Sep 19