#!/usr/bin/perl -w

use Math::Complex;
use constant dwa_pi => 6.28318530717959;

unshift @ARGV, (0) x (3 - $#ARGV);
@pierwiastki = rownanie_trzeciego_stopnia(@ARGV);
print "@pierwiastki\n";

# rownanie_liniowe($a, $b) rozwiazuje rownanie ax + b = 0 zwracajac wartosc x.
#
sub rownanie_liniowe {
    my ($a, $b) = @_;
    return unless $a;
    return -$b / $a;
}

# rownanie_kwadratowe($a, $b, $c) rozwiazuje ponizsze rownanie dla x:
#
#   2
# ax  + bx + c = 0
#
# Funkcja zwraca dwie wartosci x. W przeciwienstwie do wczesniejszej wersji
# procedury rownanie_kwadratowe() wspolczynniki a, b i c moga byc liczbami
# zespolonymi.
#
sub rownanie_kwadratowe {
    my ($a, $b, $c) = @_;

    return rownanie_liniowe($b, $c) unless $a;
    my ($sgn) = 1;
    $sgn = $b/abs($b) if $b;
    if (ref($a) || ref($b) || ref($c)) {
        my ($tmp) = Math::Complex->new(0, 0);
        $tmp = ref($b) ? ~$b : $b;
        $tmp *= sqrt($b * $b - 4 * $a * $c);
        $sgn = -1 if (ref($tmp) && $tmp->Re < 0) or $tmp < 0;
    }
    my ($tmp) = -0.5 * ($b + $sgn * sqrt($b * $b - 4 * $a * $c));
    return ($tmp / $a, $c / $tmp);
}

# rownanie_trzeciego_stopnia($a, $b, $c, $d) rozwiazuje ponizsze rownanie
# dla x:
#
#   3     2
# ax  + bx  + cx  + d = 0
#
# Funkcja zwraca liste trzech wartosci x.
#
# Procedura zaczerpnieta z ksiazki Numerical Recipes in C autorstwa Pressa i innych.
#
sub rownanie_trzeciego_stopnia {
    my ($a, $b, $c, $d) = @_;
    return rownanie_kwadratowe($b, $c, $d) unless $a;
    ($a, $b, $c) = ($b / $a, $c / $a, $d / $a);
    my ($q) = ($a ** 2 - (3 * $b)) / 9;
    my ($r) = ((2 * ($a ** 3)) - (9 * $a * $b) + (27 * $c)) / 54;
    if (!ref($q) && !ref($r) && ($r ** 2) < ($q ** 3)) {
        my ($theta) = acos($r / ($q ** 1.5));
        my ($przyrost) = -2 * sqrt($q);
        my ($odchylenie) = $a / 3;
        return ($przyrost * cos($theta / 3) - $odchylenie,
                $przyrost * cos(($theta + dwa_pi) / 3) - $odchylenie,
                $przyrost * cos(($theta - dwa_pi) / 3) - $odchylenie);
    } else {
        my ($sgn) = 1;
        my ($tmp) = sqrt($r ** 2 - $q ** 3);
        my ($rconj) = $r;
        ref($rconj) && ($rconj = ~$rconj);
        $rconj *= $tmp;
        $sgn = -1 if (ref($rconj) && $rconj->Re < 0) or $rconj < 0;
        $s = Math::Complex->new($sgn, 0);
        $s = $s * $tmp + $r;
        $s **= 1/3;
        $s = -$s;
        $t = ($s ? ($q / $s) : 0);
        return ($s + $t - $a / 3,
                -0.5 * ($s+$t) + sqrt(-1) * sqrt(3)/2 * ($s-$t) - ($a/3),
                -0.5 * ($s+$t) - sqrt(-1) * sqrt(3)/2 * ($s-$t) - ($a/3));
    }
}


