Task: Law of cosines - triples


C++: #include <cmath>
#include <iostream>
#include <tuple>
#include <vector>

using triple = std::tuple<int, int, int>;

void print_triple(std::ostream& out, const triple& t) {
    out << '(' << std::get<0>(t) << ',' << std::get<1>(t) << ',' << std::get<2>(t) << ')';
}

void print_vector(std::ostream& out, const std::vector<triple>& vec) {
    if (vec.empty())
        return;
    auto i = vec.begin();
    print_triple(out, *i++);
    for (; i != vec.end(); ++i) {
        out << ' ';
        print_triple(out, *i);
    }
    out << "\n\n";
}

int isqrt(int n) {
    return static_cast<int>(std::sqrt(n));
}

int main() {
    const int min = 1, max = 13;
    std::vector<triple> solutions90, solutions60, solutions120;

    for (int a = min; a <= max; ++a) {
        int a2 = a * a;
        for (int b = a; b <= max; ++b) {
            int b2 = b * b, ab = a * b;
            int c2 = a2 + b2;
            int c = isqrt(c2);
            if (c <= max && c * c == c2)
                solutions90.emplace_back(a, b, c);
            else {
                c2 = a2 + b2 - ab;
                c = isqrt(c2);
                if (c <= max && c * c == c2)
                    solutions60.emplace_back(a, b, c);
                else {
                    c2 = a2 + b2 + ab;
                    c = isqrt(c2);
                    if (c <= max && c * c == c2)
                        solutions120.emplace_back(a, b, c);
                }
            }
        }
    }

    std::cout << "There are " << solutions60.size() << " solutions for gamma = 60 degrees:\n";
    print_vector(std::cout, solutions60);

    std::cout << "There are " << solutions90.size() << " solutions for gamma = 90 degrees:\n";
    print_vector(std::cout, solutions90);

    std::cout << "There are " << solutions120.size() << " solutions for gamma = 120 degrees:\n";
    print_vector(std::cout, solutions120);
    
    const int max2 = 10000;
    int count = 0;
    for (int a = min; a <= max2; ++a) {
        for (int b = a + 1; b <= max2; ++b) {
            int c2 = a * a + b * b - a * b;
            int c = isqrt(c2);
            if (c <= max2 && c * c == c2)
                ++count;
        }
    }
    std::cout << "There are " << count << " solutions for gamma = 60 degrees in the range "
        << min << " to " << max2 << " where the sides are not all of the same length.\n";
    return 0;
}









Fortran: MODULE LAW_OF_COSINES
    IMPLICIT NONE

    CONTAINS

    
    REAL FUNCTION COSINE_SIDE(SIDE_A, SIDE_B, ANGLE)
        INTEGER, INTENT(IN) :: SIDE_A, SIDE_B
        REAL(8), INTENT(IN) :: ANGLE
        
        COSINE_SIDE = SIDE_A**2 + SIDE_B**2 - 2*SIDE_A*SIDE_B*COS(ANGLE)
        COSINE_SIDE = COSINE_SIDE**0.5
    END FUNCTION COSINE_SIDE

    
    REAL(8) FUNCTION DEG2RAD(ANGLE)
        REAL(8), INTENT(IN) :: ANGLE
        REAL(8), PARAMETER :: PI = 4.0D0*DATAN(1.D0)

        DEG2RAD = ANGLE*(PI/180)
    END FUNCTION DEG2RAD

    
    FUNCTION INT_SORTED(ARRAY) RESULT(SORTED)
        INTEGER, DIMENSION(:), INTENT(IN) :: ARRAY
        INTEGER, DIMENSION(SIZE(ARRAY)) :: SORTED, TEMP
        INTEGER :: MAX_VAL, DIVIDE
            
        SORTED = ARRAY
        TEMP = ARRAY
        DIVIDE = SIZE(ARRAY)

        DO WHILE (DIVIDE .NE. 1)
            MAX_VAL = MAXVAL(SORTED(1:DIVIDE))
            TEMP(DIVIDE) = MAX_VAL
            TEMP(MAXLOC(SORTED(1:DIVIDE))) = SORTED(DIVIDE)
            SORTED = TEMP
            DIVIDE = DIVIDE - 1
        END DO
    END FUNCTION INT_SORTED

    
    SUBROUTINE APPEND(ARRAY, ELEMENT)
        INTEGER, DIMENSION(:), ALLOCATABLE, INTENT(INOUT) :: ARRAY
        INTEGER, DIMENSION(:), ALLOCATABLE :: TEMP
        INTEGER :: ELEMENT
        INTEGER :: I, ISIZE

        IF (ALLOCATED(ARRAY)) THEN
            ISIZE = SIZE(ARRAY)
            ALLOCATE(TEMP(ISIZE+1))

            DO I=1, ISIZE
                TEMP(I) = ARRAY(I)
            END DO

            TEMP(ISIZE+1) = ELEMENT

            DEALLOCATE(ARRAY)

            CALL MOVE_ALLOC(TEMP, ARRAY)
        ELSE
            ALLOCATE(ARRAY(1))
            ARRAY(1) = ELEMENT
        END IF
        
    END SUBROUTINE APPEND

    
    LOGICAL FUNCTION CONTAINS_ARR(ARRAY, ELEMENT)
        INTEGER, DIMENSION(:), INTENT(IN) :: ARRAY
        INTEGER, DIMENSION(:) :: ELEMENT
        INTEGER, DIMENSION(SIZE(ELEMENT)) :: TEMP, SORTED_ELEMENT
        INTEGER :: I, COUNTER, J

        COUNTER = 0

        ELEMENT = INT_SORTED(ELEMENT)

        DO I=1,SIZE(ARRAY),SIZE(ELEMENT)
            TEMP = ARRAY(I:I+SIZE(ELEMENT)-1)
            DO J=1,SIZE(ELEMENT)
                IF (ELEMENT(J) .EQ. TEMP(J)) THEN
                    COUNTER = COUNTER + 1
                END IF
            END DO

            IF (COUNTER .EQ. SIZE(ELEMENT)) THEN
                CONTAINS_ARR = .TRUE.
                RETURN
            END IF
        END DO

        CONTAINS_ARR = .FALSE.
    END FUNCTION CONTAINS_ARR

    
    INTEGER FUNCTION COSINE_TRIPLES(MIN_NUM, MAX_NUM, ANGLE, PRINT_RESULTS) RESULT(COUNTER)
        INTEGER, INTENT(IN) :: MIN_NUM, MAX_NUM
        REAL(8), INTENT(IN) :: ANGLE
        LOGICAL, INTENT(IN) :: PRINT_RESULTS
        INTEGER, DIMENSION(:), ALLOCATABLE :: CANDIDATES
        INTEGER, DIMENSION(3) :: CANDIDATE
        INTEGER :: A, B
        REAL :: C

        COUNTER = 0

        DO A = MIN_NUM, MAX_NUM
            DO B = MIN_NUM, MAX_NUM
                C = COSINE_SIDE(A, B, DEG2RAD(ANGLE))
                IF (C .GT. MAX_NUM .OR. MOD(C, 1.) .NE. 0) THEN
                    CYCLE
                END IF

                CANDIDATE(1) = A
                CANDIDATE(2) = B
                CANDIDATE(3) = C
                IF (.NOT. CONTAINS_ARR(CANDIDATES, CANDIDATE)) THEN
                    COUNTER = COUNTER + 1
                    CALL APPEND(CANDIDATES, CANDIDATE(1))
                    CALL APPEND(CANDIDATES, CANDIDATE(2))
                    CALL APPEND(CANDIDATES, CANDIDATE(3))

                    IF (PRINT_RESULTS) THEN
                        WRITE(*,'(A,I0,A,I0,A,I0,A)') " (", CANDIDATE(1), ", ", CANDIDATE(2), ", ", CANDIDATE(3), ")"
                    END IF
                END IF
            END DO
        END DO
    END FUNCTION COSINE_TRIPLES
                  
END MODULE LAW_OF_COSINES






PROGRAM LOC
    USE LAW_OF_COSINES

    REAL(8), DIMENSION(3) :: TEST_ANGLES = (/90., 60., 120./)
    INTEGER :: I, COUNTER

    DO I = 1,SIZE(TEST_ANGLES)
        WRITE(*, '(F0.0, A)') TEST_ANGLES(I), " degree triangles: " 
        COUNTER = COSINE_TRIPLES(1, 13, TEST_ANGLES(I), .TRUE.)
        WRITE(*,'(A, I0)') "TOTAL: ", COUNTER
        WRITE(*,*) NEW_LINE('A')
    END DO

END PROGRAM LOC