0

The following code is an algorithm to determine the amount of integer triangles, with their biggest side being smaller or equal to MAX, that have an integer median. The Python version works but is too slow for bigger N, while the C++ version is a lot faster but doesn't give the right result.

When MAX is 10, C++ and Python both return 3.

When MAX is 100, Python returns 835 and C++ returns 836.

When MAX is 200, Python returns 4088 and C++ returns 4102.

When MAX is 500, Python returns 32251 and C++ returns 32296.

When MAX is 1000, Python returns 149869 and C++ returns 150002.

Here's the C++ version:

#include <cstdio>
#include <math.h>

const int MAX = 1000;

int main()
{
    long long int x = 0;
    for (int b = MAX; b > 4; b--)
    {
        printf("%lld\n", b);
        for (int a = b; a > 4; a -= 2){
            for (int c = floor(b/2); c < floor(MAX/2); c+=1)
            {
                if (a+b > 2*c){
                    int d = 2*(pow(a,2)+pow(b,2)-2*pow(c,2));
                    if (sqrt(d)/2==floor(sqrt(d)/2))
                        x+=1;
                }
            }
            }
    }
    printf("Done: ");       
    printf("%lld\n", x);
}

Here's the original Python version:

import math

def sumofSquares(n):
    f = 0
    for b in range(n,4,-1):
        print(b)
        for a in range(b,4,-2):
            for C in range(math.ceil(b/2),n//2+1):
                if a+b>2*C:
                    D = 2*(a**2+b**2-2*C**2)
                    if (math.sqrt(D)/2).is_integer():
                        f += 1
    return f

a = int(input())
print(sumofSquares(a))
print('Done')

I'm not too familiar with C++ so I have no idea what could be happening that's causing this (maybe an overflow error?).

Of course, any optimizations for the algorithm are more than welcome!

huu
  • 7,032
  • 2
  • 34
  • 49
Nicolás Siplis
  • 71
  • 3
  • 16
  • 1
    Well for one, the C++ version is using `floor` while python is using `ceil`. Also the C++ version is not dividing by 2 `if (sqrt(d)==floor(sqrt(d)))` while the python one is `if (math.sqrt(2*D)/2).is_integer():` – smac89 Apr 28 '15 at 04:29
  • The python version gives me `4` for an input of `10`. – huu Apr 28 '15 at 04:31
  • They both have the multiply by 2 (just in different places) but only the Python one has a divide by 2 after the square root. – Brad Budlong Apr 28 '15 at 04:34
  • @BradBudlong, yup just saw that, but notice that when the python version multiplies by 2, it also divides by 2 – smac89 Apr 28 '15 at 04:35
  • I can replicate your C++ results, but not your python results. – huu Apr 28 '15 at 04:35
  • pypy3 runs this _much_ faster than cpython. http://pypy.org/download.html – John La Rooy Apr 28 '15 at 04:43
  • What prevents you from putting in some `print`s in both versions and check whey do they differ? – luk32 Apr 28 '15 at 04:52
  • @huu, I have copied and pasted the code just to be sure, I don't know why it's returning a different value for you. Just in case, I've edited the codes posted and made sure both variables are multiplied and divided in the same way. – Nicolás Siplis Apr 28 '15 at 04:56
  • @JohnLaRooy I'm familiar with PyPy but C++ is still faster. – Nicolás Siplis Apr 28 '15 at 05:10
  • @NicolásSiplis, not if you include the time you've spent debugging this :) – John La Rooy Apr 28 '15 at 05:22
  • @JohnLaRooy Unfortunately, considering how long it's going to take to calculate for MAX = 100000... it is faster D: – Nicolás Siplis Apr 28 '15 at 05:23
  • @NicolásSiplis, how much faster do you guess C++ will be? – John La Rooy Apr 28 '15 at 05:35
  • @JohnLaRooy Considering this is gonna take 10^10/2 calculations (approx.), even if it were 1% faster it'd make a considerable difference. – Nicolás Siplis Apr 28 '15 at 05:39
  • @NicolásSiplis, Indeed. You probably need to port this to run on a GPU or an ASIC – John La Rooy Apr 28 '15 at 05:45
  • @JohnLaRooy Considering I'm on my first year of college... I'll wait, hehe. Would running it on a GPU significantly increase speed? I have no clue on the exact differences TBH. – Nicolás Siplis Apr 28 '15 at 05:51
  • @NicolásSiplis, Aside: For 10000, the difference between C++ and Python on my computer was between 1 and 2 percent. – John La Rooy Apr 28 '15 at 07:20

2 Answers2

1

The issue is that the range for your c (C in python) variables do not match. To make them equivalent to your existing C++ range, you can change your python loop to:

for C in range(int(math.floor(b/2)), int(math.floor(n/2))):
    ...

To make them equivalent to your existing python range, you can change your C++ loop to:

for (int c = ceil(b/2.0); c < MAX/2 + 1; c++) {
    ...
}

Depending on which loop is originally correct, this will make the results match.

huu
  • 7,032
  • 2
  • 34
  • 49
  • I just tried changing the loop in C++ but now the result is even more off. It returns 150632 when MAX is 1000! – Nicolás Siplis Apr 28 '15 at 04:53
  • 1
    What *should* be the correct answer? All my answer shows you is that your algorithms give different results because they're constructed differently. – huu Apr 28 '15 at 04:54
  • 1
    The correct answer would be 149869, the one outputted by Python. – Nicolás Siplis Apr 28 '15 at 04:57
  • I have a sneaking suspicion the algorithm you posted does not give that answer, especially when I transcribe the python algorithm to C++ I get the same result as in python. For reference, I get `150632` as well when I use your posted python algorithm, even in C++. – huu Apr 28 '15 at 04:59
  • I honestly don't know what to tell you. Just in case, I've copied and pasted the Python code in my original post and the output is 149869. C++, on the other hand, does output 150632. – Nicolás Siplis Apr 28 '15 at 05:04
  • I've got it, it's because you're using Python 3 and I'm using Python 2. I'll edit my answer to take that into account. – huu Apr 28 '15 at 05:08
  • Whew, thought I was going crazy for a moment. Thank you! – Nicolás Siplis Apr 28 '15 at 05:16
  • I've edited my answer, the C++ code should give you the same answers as your original python algorithm. – huu Apr 28 '15 at 05:24
  • It does! I don't get it though, the only difference is the 2.0 instead of a 2 (removing the int function doesn't affect the answer). So... why in the world is there any difference betwen the two? – Nicolás Siplis Apr 28 '15 at 05:30
  • When you do `b/2`, this will automatically truncate the decimal, effectively applying a floor function for positive values of `b`. When you take the `ceil` of a `floor`, that's equivalent to taking a `floor`. To get the correct `ceil`, you have to trick it into *not* truncating the decimals since the decimals are critical to your `ceil` call. You can do this by dividing by a floating point number instead of integral value, hence the `2.0`. – huu Apr 28 '15 at 05:32
  • Good to know! One thing I hate is the different ways in which each language deals with floats... I'll be sure to remember this next time, thanks! – Nicolás Siplis Apr 28 '15 at 05:37
  • In integer division, `(b+1)/2` should give the same result as `ceil(b/2.0)`. I'd avoid `pow(a,2)` etc for integer `a`, just use `a*a`. In python, `a**2` stays integer. – Lutz Lehmann Apr 28 '15 at 10:41
-1

It seams some troubles could be here:

(sqrt(d)==floor(sqrt(d))) 
Uooo
  • 6,204
  • 8
  • 36
  • 63
klatoverato
  • 35
  • 2
  • 5