Imaginary base numbers: Difference between revisions

Rename Perl 6 -> Raku, alphabetize, minor clean-up
(Added Perl example)
(Rename Perl 6 -> Raku, alphabetize, minor clean-up)
Line 617:
( 0 + 16i) -> 102000.0 -> ( 0 + 16i) ( -0 + -16i) -> 2000.0 -> ( 0 + -16i)</pre>
 
=={{header|C++ sharp|C#}}==
{{trans|C#}}
<lang cpp>#include <algorithm>
#include <complex>
#include <iomanip>
#include <iostream>
 
std::complex<double> inv(const std::complex<double>& c) {
double denom = c.real() * c.real() + c.imag() * c.imag();
return std::complex<double>(c.real() / denom, -c.imag() / denom);
}
 
class QuaterImaginary {
public:
QuaterImaginary(const std::string& s) : b2i(s) {
static std::string base("0123.");
 
if (b2i.empty()
|| std::any_of(s.cbegin(), s.cend(), [](char c) { return base.find(c) == std::string::npos; })
|| std::count(s.cbegin(), s.cend(), '.') > 1) {
throw std::runtime_error("Invalid base 2i number");
}
}
 
QuaterImaginary& operator=(const QuaterImaginary& q) {
b2i = q.b2i;
return *this;
}
 
std::complex<double> toComplex() const {
int pointPos = b2i.find('.');
int posLen = (pointPos != std::string::npos) ? pointPos : b2i.length();
std::complex<double> sum(0.0, 0.0);
std::complex<double> prod(1.0, 0.0);
for (int j = 0; j < posLen; j++) {
double k = (b2i[posLen - 1 - j] - '0');
if (k > 0.0) {
sum += prod * k;
}
prod *= twoI;
}
if (pointPos != -1) {
prod = invTwoI;
for (size_t j = posLen + 1; j < b2i.length(); j++) {
double k = (b2i[j] - '0');
if (k > 0.0) {
sum += prod * k;
}
prod *= invTwoI;
}
}
 
return sum;
}
 
friend std::ostream& operator<<(std::ostream&, const QuaterImaginary&);
 
private:
const std::complex<double> twoI{ 0.0, 2.0 };
const std::complex<double> invTwoI = inv(twoI);
 
std::string b2i;
};
 
std::ostream& operator<<(std::ostream& os, const QuaterImaginary& q) {
return os << q.b2i;
}
 
// only works properly if 'real' and 'imag' are both integral
QuaterImaginary toQuaterImaginary(const std::complex<double>& c) {
if (c.real() == 0.0 && c.imag() == 0.0) return QuaterImaginary("0");
 
int re = (int)c.real();
int im = (int)c.imag();
int fi = -1;
std::stringstream ss;
while (re != 0) {
int rem = re % -4;
re /= -4;
if (rem < 0) {
rem = 4 + rem;
re++;
}
ss << rem << 0;
}
if (im != 0) {
double f = (std::complex<double>(0.0, c.imag()) / std::complex<double>(0.0, 2.0)).real();
im = (int)ceil(f);
f = -4.0 * (f - im);
size_t index = 1;
while (im != 0) {
int rem = im % -4;
im /= -4;
if (rem < 0) {
rem = 4 + rem;
im++;
}
if (index < ss.str().length()) {
ss.str()[index] = (char)(rem + 48);
} else {
ss << 0 << rem;
}
index += 2;
}
fi = (int)f;
}
 
auto r = ss.str();
std::reverse(r.begin(), r.end());
ss.str("");
ss.clear();
ss << r;
if (fi != -1) ss << '.' << fi;
r = ss.str();
r.erase(r.begin(), std::find_if(r.begin(), r.end(), [](char c) { return c != '0'; }));
if (r[0] == '.')r = "0" + r;
return QuaterImaginary(r);
}
 
int main() {
using namespace std;
 
for (int i = 1; i <= 16; i++) {
complex<double> c1(i, 0);
QuaterImaginary qi = toQuaterImaginary(c1);
complex<double> c2 = qi.toComplex();
cout << setw(8) << c1 << " -> " << setw(8) << qi << " -> " << setw(8) << c2 << " ";
c1 = -c1;
qi = toQuaterImaginary(c1);
c2 = qi.toComplex();
cout << setw(8) << c1 << " -> " << setw(8) << qi << " -> " << setw(8) << c2 << endl;
}
cout << endl;
 
for (int i = 1; i <= 16; i++) {
complex<double> c1(0, i);
QuaterImaginary qi = toQuaterImaginary(c1);
complex<double> c2 = qi.toComplex();
cout << setw(8) << c1 << " -> " << setw(8) << qi << " -> " << setw(8) << c2 << " ";
c1 = -c1;
qi = toQuaterImaginary(c1);
c2 = qi.toComplex();
cout << setw(8) << c1 << " -> " << setw(8) << qi << " -> " << setw(8) << c2 << endl;
}
 
return 0;
}</lang>
{{out}}
<pre> (1,0) -> 1 -> (1,0) (-1,-0) -> 103 -> (-1,0)
(2,0) -> 2 -> (2,0) (-2,-0) -> 102 -> (-2,0)
(3,0) -> 3 -> (3,0) (-3,-0) -> 101 -> (-3,0)
(4,0) -> 10300 -> (4,0) (-4,-0) -> 100 -> (-4,0)
(5,0) -> 10301 -> (5,0) (-5,-0) -> 203 -> (-5,0)
(6,0) -> 10302 -> (6,0) (-6,-0) -> 202 -> (-6,0)
(7,0) -> 10303 -> (7,0) (-7,-0) -> 201 -> (-7,0)
(8,0) -> 10200 -> (8,0) (-8,-0) -> 200 -> (-8,0)
(9,0) -> 10201 -> (9,0) (-9,-0) -> 303 -> (-9,0)
(10,0) -> 10202 -> (10,0) (-10,-0) -> 302 -> (-10,0)
(11,0) -> 10203 -> (11,0) (-11,-0) -> 301 -> (-11,0)
(12,0) -> 10100 -> (12,0) (-12,-0) -> 300 -> (-12,0)
(13,0) -> 10101 -> (13,0) (-13,-0) -> 1030003 -> (-13,0)
(14,0) -> 10102 -> (14,0) (-14,-0) -> 1030002 -> (-14,0)
(15,0) -> 10103 -> (15,0) (-15,-0) -> 1030001 -> (-15,0)
(16,0) -> 10000 -> (16,0) (-16,-0) -> 1030000 -> (-16,0)
 
(0,1) -> 10.2 -> (0,1) (-0,-1) -> 0.2 -> (0,-1)
(0,2) -> 10.0 -> (0,2) (-0,-2) -> 1030.0 -> (0,-2)
(0,3) -> 20.2 -> (0,3) (-0,-3) -> 1030.2 -> (0,-3)
(0,4) -> 20.0 -> (0,4) (-0,-4) -> 1020.0 -> (0,-4)
(0,5) -> 30.2 -> (0,5) (-0,-5) -> 1020.2 -> (0,-5)
(0,6) -> 30.0 -> (0,6) (-0,-6) -> 1010.0 -> (0,-6)
(0,7) -> 103000.2 -> (0,7) (-0,-7) -> 1010.2 -> (0,-7)
(0,8) -> 103000.0 -> (0,8) (-0,-8) -> 1000.0 -> (0,-8)
(0,9) -> 103010.2 -> (0,9) (-0,-9) -> 1000.2 -> (0,-9)
(0,10) -> 103010.0 -> (0,10) (-0,-10) -> 2030.0 -> (0,-10)
(0,11) -> 103020.2 -> (0,11) (-0,-11) -> 2030.2 -> (0,-11)
(0,12) -> 103020.0 -> (0,12) (-0,-12) -> 2020.0 -> (0,-12)
(0,13) -> 103030.2 -> (0,13) (-0,-13) -> 2020.2 -> (0,-13)
(0,14) -> 103030.0 -> (0,14) (-0,-14) -> 2010.0 -> (0,-14)
(0,15) -> 102000.2 -> (0,15) (-0,-15) -> 2010.2 -> (0,-15)
(0,16) -> 102000.0 -> (0,16) (-0,-16) -> 2000.0 -> (0,-16)</pre>
 
=={{header|C#|C sharp}}==
<lang csharp>using System;
using System.Linq;
Line 1,011 ⟶ 829:
15i -> 102000.2 -> 15i -15i -> 2010.2 -> -15i
16i -> 102000.0 -> 16i -16i -> 2000.0 -> -16i</pre>
 
=={{header|C++}}==
{{trans|C#}}
<lang cpp>#include <algorithm>
#include <complex>
#include <iomanip>
#include <iostream>
 
std::complex<double> inv(const std::complex<double>& c) {
double denom = c.real() * c.real() + c.imag() * c.imag();
return std::complex<double>(c.real() / denom, -c.imag() / denom);
}
 
class QuaterImaginary {
public:
QuaterImaginary(const std::string& s) : b2i(s) {
static std::string base("0123.");
 
if (b2i.empty()
|| std::any_of(s.cbegin(), s.cend(), [](char c) { return base.find(c) == std::string::npos; })
|| std::count(s.cbegin(), s.cend(), '.') > 1) {
throw std::runtime_error("Invalid base 2i number");
}
}
 
QuaterImaginary& operator=(const QuaterImaginary& q) {
b2i = q.b2i;
return *this;
}
 
std::complex<double> toComplex() const {
int pointPos = b2i.find('.');
int posLen = (pointPos != std::string::npos) ? pointPos : b2i.length();
std::complex<double> sum(0.0, 0.0);
std::complex<double> prod(1.0, 0.0);
for (int j = 0; j < posLen; j++) {
double k = (b2i[posLen - 1 - j] - '0');
if (k > 0.0) {
sum += prod * k;
}
prod *= twoI;
}
if (pointPos != -1) {
prod = invTwoI;
for (size_t j = posLen + 1; j < b2i.length(); j++) {
double k = (b2i[j] - '0');
if (k > 0.0) {
sum += prod * k;
}
prod *= invTwoI;
}
}
 
return sum;
}
 
friend std::ostream& operator<<(std::ostream&, const QuaterImaginary&);
 
private:
const std::complex<double> twoI{ 0.0, 2.0 };
const std::complex<double> invTwoI = inv(twoI);
 
std::string b2i;
};
 
std::ostream& operator<<(std::ostream& os, const QuaterImaginary& q) {
return os << q.b2i;
}
 
// only works properly if 'real' and 'imag' are both integral
QuaterImaginary toQuaterImaginary(const std::complex<double>& c) {
if (c.real() == 0.0 && c.imag() == 0.0) return QuaterImaginary("0");
 
int re = (int)c.real();
int im = (int)c.imag();
int fi = -1;
std::stringstream ss;
while (re != 0) {
int rem = re % -4;
re /= -4;
if (rem < 0) {
rem = 4 + rem;
re++;
}
ss << rem << 0;
}
if (im != 0) {
double f = (std::complex<double>(0.0, c.imag()) / std::complex<double>(0.0, 2.0)).real();
im = (int)ceil(f);
f = -4.0 * (f - im);
size_t index = 1;
while (im != 0) {
int rem = im % -4;
im /= -4;
if (rem < 0) {
rem = 4 + rem;
im++;
}
if (index < ss.str().length()) {
ss.str()[index] = (char)(rem + 48);
} else {
ss << 0 << rem;
}
index += 2;
}
fi = (int)f;
}
 
auto r = ss.str();
std::reverse(r.begin(), r.end());
ss.str("");
ss.clear();
ss << r;
if (fi != -1) ss << '.' << fi;
r = ss.str();
r.erase(r.begin(), std::find_if(r.begin(), r.end(), [](char c) { return c != '0'; }));
if (r[0] == '.')r = "0" + r;
return QuaterImaginary(r);
}
 
int main() {
using namespace std;
 
for (int i = 1; i <= 16; i++) {
complex<double> c1(i, 0);
QuaterImaginary qi = toQuaterImaginary(c1);
complex<double> c2 = qi.toComplex();
cout << setw(8) << c1 << " -> " << setw(8) << qi << " -> " << setw(8) << c2 << " ";
c1 = -c1;
qi = toQuaterImaginary(c1);
c2 = qi.toComplex();
cout << setw(8) << c1 << " -> " << setw(8) << qi << " -> " << setw(8) << c2 << endl;
}
cout << endl;
 
for (int i = 1; i <= 16; i++) {
complex<double> c1(0, i);
QuaterImaginary qi = toQuaterImaginary(c1);
complex<double> c2 = qi.toComplex();
cout << setw(8) << c1 << " -> " << setw(8) << qi << " -> " << setw(8) << c2 << " ";
c1 = -c1;
qi = toQuaterImaginary(c1);
c2 = qi.toComplex();
cout << setw(8) << c1 << " -> " << setw(8) << qi << " -> " << setw(8) << c2 << endl;
}
 
return 0;
}</lang>
{{out}}
<pre> (1,0) -> 1 -> (1,0) (-1,-0) -> 103 -> (-1,0)
(2,0) -> 2 -> (2,0) (-2,-0) -> 102 -> (-2,0)
(3,0) -> 3 -> (3,0) (-3,-0) -> 101 -> (-3,0)
(4,0) -> 10300 -> (4,0) (-4,-0) -> 100 -> (-4,0)
(5,0) -> 10301 -> (5,0) (-5,-0) -> 203 -> (-5,0)
(6,0) -> 10302 -> (6,0) (-6,-0) -> 202 -> (-6,0)
(7,0) -> 10303 -> (7,0) (-7,-0) -> 201 -> (-7,0)
(8,0) -> 10200 -> (8,0) (-8,-0) -> 200 -> (-8,0)
(9,0) -> 10201 -> (9,0) (-9,-0) -> 303 -> (-9,0)
(10,0) -> 10202 -> (10,0) (-10,-0) -> 302 -> (-10,0)
(11,0) -> 10203 -> (11,0) (-11,-0) -> 301 -> (-11,0)
(12,0) -> 10100 -> (12,0) (-12,-0) -> 300 -> (-12,0)
(13,0) -> 10101 -> (13,0) (-13,-0) -> 1030003 -> (-13,0)
(14,0) -> 10102 -> (14,0) (-14,-0) -> 1030002 -> (-14,0)
(15,0) -> 10103 -> (15,0) (-15,-0) -> 1030001 -> (-15,0)
(16,0) -> 10000 -> (16,0) (-16,-0) -> 1030000 -> (-16,0)
 
(0,1) -> 10.2 -> (0,1) (-0,-1) -> 0.2 -> (0,-1)
(0,2) -> 10.0 -> (0,2) (-0,-2) -> 1030.0 -> (0,-2)
(0,3) -> 20.2 -> (0,3) (-0,-3) -> 1030.2 -> (0,-3)
(0,4) -> 20.0 -> (0,4) (-0,-4) -> 1020.0 -> (0,-4)
(0,5) -> 30.2 -> (0,5) (-0,-5) -> 1020.2 -> (0,-5)
(0,6) -> 30.0 -> (0,6) (-0,-6) -> 1010.0 -> (0,-6)
(0,7) -> 103000.2 -> (0,7) (-0,-7) -> 1010.2 -> (0,-7)
(0,8) -> 103000.0 -> (0,8) (-0,-8) -> 1000.0 -> (0,-8)
(0,9) -> 103010.2 -> (0,9) (-0,-9) -> 1000.2 -> (0,-9)
(0,10) -> 103010.0 -> (0,10) (-0,-10) -> 2030.0 -> (0,-10)
(0,11) -> 103020.2 -> (0,11) (-0,-11) -> 2030.2 -> (0,-11)
(0,12) -> 103020.0 -> (0,12) (-0,-12) -> 2020.0 -> (0,-12)
(0,13) -> 103030.2 -> (0,13) (-0,-13) -> 2020.2 -> (0,-13)
(0,14) -> 103030.0 -> (0,14) (-0,-14) -> 2010.0 -> (0,-14)
(0,15) -> 102000.2 -> (0,15) (-0,-15) -> 2010.2 -> (0,-15)
(0,16) -> 102000.0 -> (0,16) (-0,-16) -> 2000.0 -> (0,-16)</pre>
 
=={{header|D}}==
Line 2,559:
 
base( 6i): 31432.6219135802-2898.5266203704*i => perl5.4ever</pre>
 
=={{header|Perl 6}}==
{{works with|Rakudo|2017.01}}
These are generalized imaginary-base conversion routines. They only work for imaginary bases, not complex. (Any real portion of the radix must be zero.) Theoretically they could be made to work for any imaginary base; in practice, they are limited to integer bases from -6i to -2i and 2i to 6i. Bases -1i and 1i exist but require special handling and are not supported. Bases larger than 6i (or -6i) require digits outside of base 36 to express them, so aren't as standardized, are implementation dependent and are not supported. Note that imaginary number coefficients are stored as floating point numbers in Perl 6 so some rounding error may creep in during calculations. The precision these conversion routines use is configurable; we are using 6 <strike>decimal</strike>, um... radicimal(?) places of precision here.
 
Implements minimum, extra kudos and stretch goals.
 
<lang perl6>multi sub base ( Real $num, Int $radix where -37 < * < -1, :$precision = -15 ) {
return '0' unless $num;
my $value = $num;
my $result = '';
my $place = 0;
my $upper-bound = 1 / (-$radix + 1);
my $lower-bound = $radix * $upper-bound;
 
$value = $num / $radix ** ++$place until $lower-bound <= $value < $upper-bound;
 
while ($value or $place > 0) and $place > $precision {
my $digit = ($radix * $value - $lower-bound).Int;
$value = $radix * $value - $digit;
$result ~= '.' unless $place or $result.contains: '.';
$result ~= $digit == -$radix ?? ($digit-1).base(-$radix)~'0' !! $digit.base(-$radix);
$place--
}
$result
}
 
multi sub base (Numeric $num, Complex $radix where *.re == 0, :$precision = -8 ) {
die "Base $radix out of range" unless -6 <= $radix.im <= -2 or 2 <= $radix.im <= 6;
my ($re, $im) = $num.Complex.reals;
my ($re-wh, $re-fr) = $re.&base( -$radix.im².Int, :precision($precision) ).split: '.';
my ($im-wh, $im-fr) = ($im/$radix.im).&base( -$radix.im².Int, :precision($precision) ).split: '.';
$_ //= '' for $re-fr, $im-fr;
 
sub zip (Str $a, Str $b) {
my $l = '0' x ($a.chars - $b.chars).abs;
([~] flat ($a~$l).comb Z flat ($b~$l).comb).subst(/ '0'+ $ /, '') || '0'
}
 
my $whole = flip zip $re-wh.flip, $im-wh.flip;
my $fraction = zip $im-fr, $re-fr;
$fraction eq 0 ?? "$whole" !! "$whole.$fraction"
}
 
multi sub parse-base (Str $str, Complex $radix where *.re == 0) {
return -1 * $str.substr(1).&parse-base($radix) if $str.substr(0,1) eq '-';
my ($whole, $frac) = $str.split: '.';
my $fraction = 0;
$fraction = [+] $frac.comb.kv.map: { $^v.parse-base($radix.im².Int) * $radix ** -($^k+1) } if $frac;
$fraction + [+] $whole.flip.comb.kv.map: { $^v.parse-base($radix.im².Int) * $radix ** $^k }
}
 
# TESTING
for 0, 2i, 1, 2i, 5, 2i, -13, 2i, 9i, 2i, -3i, 2i, 7.75-7.5i, 2i, .25, 2i, # base 2i tests
5+5i, 2i, 5+5i, 3i, 5+5i, 4i, 5+5i, 5i, 5+5i, 6i, # same value, positive imaginary bases
5+5i, -2i, 5+5i, -3i, 5+5i, -4i, 5+5i, -5i, 5+5i, -6i, # same value, negative imaginary bases
227.65625+10.859375i, 4i, # larger test value
31433.3487654321-2902.4480452675i, 6i # heh
-> $v, $r {
my $ibase = $v.&base($r, :precision(-6));
printf "%33s.&base\(%2si\) = %-11s : %13s.&parse-base\(%2si\) = %s\n",
$v, $r.im, $ibase, "'$ibase'", $r.im, $ibase.&parse-base($r).round(1e-10).narrow;
}</lang>
{{out}}
<pre> 0.&base( 2i) = 0 : '0'.&parse-base( 2i) = 0
1.&base( 2i) = 1 : '1'.&parse-base( 2i) = 1
5.&base( 2i) = 10301 : '10301'.&parse-base( 2i) = 5
-13.&base( 2i) = 1030003 : '1030003'.&parse-base( 2i) = -13
0+9i.&base( 2i) = 103010.2 : '103010.2'.&parse-base( 2i) = 0+9i
-0-3i.&base( 2i) = 1030.2 : '1030.2'.&parse-base( 2i) = 0-3i
7.75-7.5i.&base( 2i) = 11210.31 : '11210.31'.&parse-base( 2i) = 7.75-7.5i
0.25.&base( 2i) = 1.03 : '1.03'.&parse-base( 2i) = 0.25
5+5i.&base( 2i) = 10331.2 : '10331.2'.&parse-base( 2i) = 5+5i
5+5i.&base( 3i) = 25.3 : '25.3'.&parse-base( 3i) = 5+5i
5+5i.&base( 4i) = 25.C : '25.C'.&parse-base( 4i) = 5+5i
5+5i.&base( 5i) = 15 : '15'.&parse-base( 5i) = 5+5i
5+5i.&base( 6i) = 15.6 : '15.6'.&parse-base( 6i) = 5+5i
5+5i.&base(-2i) = 11321.2 : '11321.2'.&parse-base(-2i) = 5+5i
5+5i.&base(-3i) = 1085.6 : '1085.6'.&parse-base(-3i) = 5+5i
5+5i.&base(-4i) = 10F5.4 : '10F5.4'.&parse-base(-4i) = 5+5i
5+5i.&base(-5i) = 10O5 : '10O5'.&parse-base(-5i) = 5+5i
5+5i.&base(-6i) = 5.U : '5.U'.&parse-base(-6i) = 5+5i
227.65625+10.859375i.&base( 4i) = 10234.5678 : '10234.5678'.&parse-base( 4i) = 227.65625+10.859375i
31433.3487654321-2902.4480452675i.&base( 6i) = PERL6.ROCKS : 'PERL6.ROCKS'.&parse-base( 6i) = 31433.3487654321-2902.4480452675i</pre>
 
=={{header|Phix}}==
Line 2,928 ⟶ 2,844:
16j -> 102000.0 -> 16j (-0-16j) -> 2000.0 -> -16j
done</pre>
 
=={{header|Raku}}==
(formerly Perl 6)
{{works with|Rakudo|2017.01}}
These are generalized imaginary-base conversion routines. They only work for imaginary bases, not complex. (Any real portion of the radix must be zero.) Theoretically they could be made to work for any imaginary base; in practice, they are limited to integer bases from -6i to -2i and 2i to 6i. Bases -1i and 1i exist but require special handling and are not supported. Bases larger than 6i (or -6i) require digits outside of base 36 to express them, so aren't as standardized, are implementation dependent and are not supported. Note that imaginary number coefficients are stored as floating point numbers in Perl 6 so some rounding error may creep in during calculations. The precision these conversion routines use is configurable; we are using 6 <strike>decimal</strike>, um... radicimal(?) places of precision here.
 
Implements minimum, extra kudos and stretch goals.
 
<lang perl6>multi sub base ( Real $num, Int $radix where -37 < * < -1, :$precision = -15 ) {
return '0' unless $num;
my $value = $num;
my $result = '';
my $place = 0;
my $upper-bound = 1 / (-$radix + 1);
my $lower-bound = $radix * $upper-bound;
 
$value = $num / $radix ** ++$place until $lower-bound <= $value < $upper-bound;
 
while ($value or $place > 0) and $place > $precision {
my $digit = ($radix * $value - $lower-bound).Int;
$value = $radix * $value - $digit;
$result ~= '.' unless $place or $result.contains: '.';
$result ~= $digit == -$radix ?? ($digit-1).base(-$radix)~'0' !! $digit.base(-$radix);
$place--
}
$result
}
 
multi sub base (Numeric $num, Complex $radix where *.re == 0, :$precision = -8 ) {
die "Base $radix out of range" unless -6 <= $radix.im <= -2 or 2 <= $radix.im <= 6;
my ($re, $im) = $num.Complex.reals;
my ($re-wh, $re-fr) = $re.&base( -$radix.im².Int, :precision($precision) ).split: '.';
my ($im-wh, $im-fr) = ($im/$radix.im).&base( -$radix.im².Int, :precision($precision) ).split: '.';
$_ //= '' for $re-fr, $im-fr;
 
sub zip (Str $a, Str $b) {
my $l = '0' x ($a.chars - $b.chars).abs;
([~] flat ($a~$l).comb Z flat ($b~$l).comb).subst(/ '0'+ $ /, '') || '0'
}
 
my $whole = flip zip $re-wh.flip, $im-wh.flip;
my $fraction = zip $im-fr, $re-fr;
$fraction eq 0 ?? "$whole" !! "$whole.$fraction"
}
 
multi sub parse-base (Str $str, Complex $radix where *.re == 0) {
return -1 * $str.substr(1).&parse-base($radix) if $str.substr(0,1) eq '-';
my ($whole, $frac) = $str.split: '.';
my $fraction = 0;
$fraction = [+] $frac.comb.kv.map: { $^v.parse-base($radix.im².Int) * $radix ** -($^k+1) } if $frac;
$fraction + [+] $whole.flip.comb.kv.map: { $^v.parse-base($radix.im².Int) * $radix ** $^k }
}
 
# TESTING
for 0, 2i, 1, 2i, 5, 2i, -13, 2i, 9i, 2i, -3i, 2i, 7.75-7.5i, 2i, .25, 2i, # base 2i tests
5+5i, 2i, 5+5i, 3i, 5+5i, 4i, 5+5i, 5i, 5+5i, 6i, # same value, positive imaginary bases
5+5i, -2i, 5+5i, -3i, 5+5i, -4i, 5+5i, -5i, 5+5i, -6i, # same value, negative imaginary bases
227.65625+10.859375i, 4i, # larger test value
31433.3487654321-2902.4480452675i, 6i # heh
-> $v, $r {
my $ibase = $v.&base($r, :precision(-6));
printf "%33s.&base\(%2si\) = %-11s : %13s.&parse-base\(%2si\) = %s\n",
$v, $r.im, $ibase, "'$ibase'", $r.im, $ibase.&parse-base($r).round(1e-10).narrow;
}</lang>
{{out}}
<pre> 0.&base( 2i) = 0 : '0'.&parse-base( 2i) = 0
1.&base( 2i) = 1 : '1'.&parse-base( 2i) = 1
5.&base( 2i) = 10301 : '10301'.&parse-base( 2i) = 5
-13.&base( 2i) = 1030003 : '1030003'.&parse-base( 2i) = -13
0+9i.&base( 2i) = 103010.2 : '103010.2'.&parse-base( 2i) = 0+9i
-0-3i.&base( 2i) = 1030.2 : '1030.2'.&parse-base( 2i) = 0-3i
7.75-7.5i.&base( 2i) = 11210.31 : '11210.31'.&parse-base( 2i) = 7.75-7.5i
0.25.&base( 2i) = 1.03 : '1.03'.&parse-base( 2i) = 0.25
5+5i.&base( 2i) = 10331.2 : '10331.2'.&parse-base( 2i) = 5+5i
5+5i.&base( 3i) = 25.3 : '25.3'.&parse-base( 3i) = 5+5i
5+5i.&base( 4i) = 25.C : '25.C'.&parse-base( 4i) = 5+5i
5+5i.&base( 5i) = 15 : '15'.&parse-base( 5i) = 5+5i
5+5i.&base( 6i) = 15.6 : '15.6'.&parse-base( 6i) = 5+5i
5+5i.&base(-2i) = 11321.2 : '11321.2'.&parse-base(-2i) = 5+5i
5+5i.&base(-3i) = 1085.6 : '1085.6'.&parse-base(-3i) = 5+5i
5+5i.&base(-4i) = 10F5.4 : '10F5.4'.&parse-base(-4i) = 5+5i
5+5i.&base(-5i) = 10O5 : '10O5'.&parse-base(-5i) = 5+5i
5+5i.&base(-6i) = 5.U : '5.U'.&parse-base(-6i) = 5+5i
227.65625+10.859375i.&base( 4i) = 10234.5678 : '10234.5678'.&parse-base( 4i) = 227.65625+10.859375i
31433.3487654321-2902.4480452675i.&base( 6i) = PERL6.ROCKS : 'PERL6.ROCKS'.&parse-base( 6i) = 31433.3487654321-2902.4480452675i</pre>
 
=={{header|Sidef}}==
10,333

edits