From Code to Community: Sponsoring The Perl and Raku Conference 2025 Learn more

use strict;
use Math::FakeDD qw(:all);
use Config;
my $nan = dd_nan(); # nan
my $pinf = dd_inf(); # +ve inf
my $ninf = dd_inf(-1); # -ve inf
my $pzero = Math::FakeDD->new(0);
my $nzero = $pzero * -1;
my $dd_denorm_min = Math::FakeDD->new(Math::FakeDD::DBL_DENORM_MIN);
my ($dd1, $dd2,$rt);
cmp_ok(ulp_exponent($pinf), '==', -1074, "ulp_exponent(inf) returns -1074");
cmp_ok(ulp_exponent($ninf), '==', -1074, "ulp_exponent(-inf) returns -1074");
cmp_ok(ulp_exponent($nan), '==', -1074, "ulp_exponent(nan) returns -1074");
cmp_ok(ulp_exponent($pzero), '==', -1074, "ulp_exponent(0) returns -1074");
cmp_ok(ulp_exponent($nzero), '==', -1074, "ulp_exponent(-0) returns -1074");
# Run some checks on is_subnormal()
cmp_ok(is_subnormal($pinf->{msd}), '==', 0, "is_subnormal(inf) returns 0");
cmp_ok(is_subnormal($ninf->{msd}), '==', 0, "is_subnormal(-inf) returns 0");
cmp_ok(is_subnormal($nan->{msd}), '==', 0, "is_subnormal(nan) returns 0");
cmp_ok(is_subnormal($pzero->{msd}), '==', 1, "is_subnormal(0) returns 1");
cmp_ok(is_subnormal($nzero->{msd}), '==', 1, "is_subnormal(-0) returns 1");
cmp_ok(is_subnormal(2**-1022), '==', 0, "is_subnormal(2**-1022) returns 0");
cmp_ok(is_subnormal(2**-1023), '==', 1, "is_subnormal(2**-1023) returns 1");
cmp_ok(is_subnormal(2**-1022 + 2**-1023), '==', 0, "is_subnormal(2**-1022 + 2**-1023) returns 0");
cmp_ok(is_subnormal(2**-1022 - 2**-1074), '==', 1, "is_subnormal(2**-1022 - 2**-1074) returns 1");
my $nu = dd_nextup($nan);
cmp_ok(dd_is_nan($nu), '==', 1, "nextup from NaN is NaN");
my $nd= dd_nextdown($nan);
cmp_ok(dd_is_nan($nd), '==', 1, "nextdown from NaN is NaN");
$nu = dd_nextup($pinf);
cmp_ok($nu, '>', 0, "nextup from +Inf is greater than 0");
cmp_ok(dd_is_inf($nu), '==', 1, "nextup from +Inf is Inf");
$nd = dd_nextdown($pinf);
cmp_ok($nd, '==', $Math::FakeDD::DD_MAX, "nextdown from +Inf is " . $Math::FakeDD::DD_MAX);
cmp_ok(dd_is_inf(dd_nextup($nd)), '==', 1, 'nextup from $Math::FakeDD::DD_MAX is inf');
$nu = dd_nextup($ninf);
cmp_ok($nu, '==', -$Math::FakeDD::DD_MAX, "nextup from -Inf is " . -$Math::FakeDD::DD_MAX);
$nd = dd_nextdown($ninf);
cmp_ok($nd, '<', 0, "nextdown from -Inf is less than 0");
cmp_ok(dd_is_inf($nd), '!=', 0, "nextdown from -Inf is Inf");
if(4 > Math::MPFR::MPFR_VERSION_MAJOR ) {
warn "Skipping tests that rely on mpfr library being at version 4 or later\n";
done_testing();
exit 0;
}
$nu = dd_nextup($pzero);
cmp_ok($nu, '==', Math::FakeDD::DBL_DENORM_MIN, "nextup from +0 is $dd_denorm_min");
$nd = dd_nextdown($pzero);
cmp_ok($nd, '==', -Math::FakeDD::DBL_DENORM_MIN, "nextdown from +0 is " . -$dd_denorm_min);
$nu = dd_nextup($nzero);
cmp_ok($nu, '==', Math::FakeDD::DBL_DENORM_MIN, "nextup from -0 is $dd_denorm_min");
$nd = dd_nextdown($nzero);
cmp_ok($nd, '==', -Math::FakeDD::DBL_DENORM_MIN, "nextdown from +0 is " . -$dd_denorm_min);
my $dd_norm_min = Math::FakeDD->new(2 ** -1022);
my $dd_subnorm_max = dd_nextdown($dd_norm_min);
cmp_ok(is_subnormal($dd_subnorm_max->{msd}), '==', 1, "nextdown from 2**-1022 is subnormal");
cmp_ok(dd_nextup($dd_subnorm_max), '==', $dd_norm_min, "nextup from max subnormal is normal");
###############################################################################################
my $dd = Math::FakeDD->new(2 ** -1022) + (2 ** -1074);
# [2.225073858507202e-308 0.0]
$nu = dd_nextup($dd);
# [2.2250738585072024e-308 0.0]
cmp_ok($nu, '==', Math::FakeDD->new(2 **-1022) + (2 ** -1073),
"dd_nextup(2 ** -1022) + (2 ** -1074)) == (2 ** -1022) + (2 ** -1073)");
cmp_ok($nu - $dd, '==', Math::FakeDD->new(2 ** ulp_exponent($dd)), "$nu - $dd ok");
$nd = dd_nextdown($dd);
# [2.2250738585072014e-308 0.0]
cmp_ok($nd, '==', Math::FakeDD->new(2 **-1022),
"dd_nextdown(2 ** -1022) + (2 ** -1074)) == (2 ** -1022)");
cmp_ok($dd - $nd, '==', Math::FakeDD->new(2 ** ulp_exponent($dd)), "$dd - $nd ok");
cmp_ok($dd, '==', dd_nextup($nd), "up-down " . sprintx($dd) . " survives round_trip");
cmp_ok($dd, '==', dd_nextdown($nu), "down-up " . sprintx($dd) . " survives round_trip");
$dd = Math::FakeDD->new(-(2 ** -1022)) - (2 ** -1074);
# [-2.225073858507202e-308 0.0]
$nu = dd_nextup($dd);
# [-2.2250738585072014e-308 0.0]
cmp_ok($nu, '==', Math::FakeDD->new(-(2 **-1022)),
"dd_nextup(-(2 ** -1022)) - (2 ** -1074)) == -(2 ** -1022)");
cmp_ok($nu - $dd, '==', Math::FakeDD->new(2 ** ulp_exponent($dd)), "$nu - $dd ok");
$nd = dd_nextdown($dd);
# [-2.2250738585072024e-308 0.0]
cmp_ok($nd, '==', Math::FakeDD->new(-(2 **-1022)) - (2 ** -1073),
"dd_nextdown(-(2 ** -1022)) - (2 ** -1074)) == -(2 ** -1022) - (2 ** -1073)");
cmp_ok($dd - $nd, '==', Math::FakeDD->new(2 ** ulp_exponent($dd)), "$dd - $nd ok");
cmp_ok($dd, '==', dd_nextup($nd), "up-down " . sprintx($dd) . " survives round_trip");
cmp_ok($dd, '==', dd_nextdown($nu), "down-up " . sprintx($dd) . " survives round_trip");
###############################################################################################
###############################################################################################
$dd = Math::FakeDD->new(2 ** -1000) + (2 ** -1052);
# [9.33263618503219e-302 0.0]
$nu = dd_nextup($dd);
# [9.33263618503219e-302 5e-324]
cmp_ok($nu, '==', Math::FakeDD->new(2 **-1000) + (2 ** -1052) + Math::FakeDD::DBL_DENORM_MIN,
"dd_nextup(2 ** -1000) + (2 ** -1052)) == (2 ** -1000) + (2 ** -1052) + (2 ** -1074)");
cmp_ok($nu - $dd, '==', Math::FakeDD->new(2 ** ulp_exponent($dd)), "$nu - $dd ok");
$nd = dd_nextdown($dd);
# [9.33263618503219e-302 -5e-324]
cmp_ok($nd, '==', Math::FakeDD->new(2 **-1000) + (2 ** -1052) - Math::FakeDD::DBL_DENORM_MIN,
"dd_nextdown(2 ** -1000) + (2 ** -1052)) == (2 ** -1000) + (2 ** -1052) -(2 ** -1074)");
cmp_ok($dd - $nd, '==', Math::FakeDD->new(2 ** ulp_exponent($dd)), "$dd - $nd ok");
cmp_ok($dd, '==', dd_nextup($nd), "up-down " . sprintx($dd) . " survives round_trip");
cmp_ok($dd, '==', dd_nextdown($nu), "down-up " . sprintx($dd) . " survives round_trip");
$dd = Math::FakeDD->new(-(2 ** -1000)) - (2 ** -1052);
# [-9.33263618503219e-302 0.0]
$nu = dd_nextup($dd);
# [-9.33263618503219e-302 5e-324]
cmp_ok($nu, '==', Math::FakeDD->new(-(2 **-1000)) - (2 ** -1052) + Math::FakeDD::DBL_DENORM_MIN,
"dd_nextup(-(2 ** -1000)) - (2 ** -1052)) == -(2 ** -1000) -(2 ** -1052) + (2 ** -1074)");
cmp_ok($nu - $dd, '==', Math::FakeDD->new(2 ** ulp_exponent($dd)), "$nu - $dd ok");
$nd = dd_nextdown($dd);
# [-9.33263618503219e-302 -5e-324]
cmp_ok($nd, '==', Math::FakeDD->new(-(2 **-1000)) - (2 ** -1052) - Math::FakeDD::DBL_DENORM_MIN,
"dd_nextdown(-(2 ** -1000)) - (2 ** -1052)) == -(2 ** -1000) - (2 ** -1052) -(2 ** -1074)");
cmp_ok($dd - $nd, '==', Math::FakeDD->new(2 ** ulp_exponent($dd)), "$dd - $nd ok");
cmp_ok($dd, '==', dd_nextup($nd), "up-down " . sprintx($dd) . " survives round_trip");
cmp_ok($dd, '==', dd_nextdown($nu), "down-up " . sprintx($dd) . " survives round_trip");
###############################################################################################
for(1 .. 100) {
my $p1 = int(rand(1024));
$p1 *= -1 if $_ % 2; # check for equal numbers of -ve and +ve powers
my $p2 = $p1 - int(rand(52));
my $first = 2 ** $p1;
my $second = 2 ** $p2;
$dd = Math::FakeDD->new($first) + $second;
if(dd_is_inf($dd)) {
# AFAICT, this will happen only when int(rand(1024)) returns
# 1023 && int(rand(52) returns 0. But this has happened:
cmp_ok(dd_nextup($dd), '==', dd_inf(), "nextup(inf) is inf");
next; # remaining tests don't cater for Inf.
}
$nu = dd_nextup($dd);
cmp_ok($nu, '==', Math::FakeDD->new($first) + ($second) + Math::FakeDD::DBL_DENORM_MIN,
"dd_nextup(2**$p1) + (2**$p2)) == (2**$p1) + (2**$p2) + (2 ** -1074)");
cmp_ok($nu - $dd, '==', Math::FakeDD->new(2 ** ulp_exponent($dd)), "$nu - $dd ok"); ## line 167
$nd = dd_nextdown($dd);
cmp_ok($nd, '==', Math::FakeDD->new($first) + ($second) - Math::FakeDD::DBL_DENORM_MIN,
"dd_nextdown(2**$p1) + (2**$p2)) == (2**$p1) + (2**$p2) -(2 ** -1074)");
cmp_ok($dd - $nd, '==', Math::FakeDD->new(2 ** ulp_exponent($dd)), "$dd - $nd ok");
cmp_ok($dd, '==', dd_nextup($nd), "up-down " . sprintx($dd) . " survives round_trip");
cmp_ok($dd, '==', dd_nextdown($nu), "down-up " . sprintx($dd) . " survives round_trip");
$first *= -1;
$dd = Math::FakeDD->new($first) + $second;
$nu = dd_nextup($dd);
cmp_ok($nu, '==', Math::FakeDD->new($first) + ($second) + Math::FakeDD::DBL_DENORM_MIN,
"dd_nextup(2**$p1) + (2**$p2)) == (2**$p1) + (2**$p2) + (2 ** -1074)");
cmp_ok($nu - $dd, '==', Math::FakeDD->new(2 ** ulp_exponent($dd)), "$nu - $dd ok");
$nd = dd_nextdown($dd);
cmp_ok($nd, '==', Math::FakeDD->new($first) + ($second) - Math::FakeDD::DBL_DENORM_MIN,
"dd_nextdown(2**$p1) + (2**$p2)) == (2**$p1) + (2**$p2) -(2 ** -1074)");
cmp_ok($dd - $nd, '==', Math::FakeDD->new(2 ** ulp_exponent($dd)), "$dd - $nd ok");
cmp_ok($dd, '==', dd_nextup($nd), "up-down " . sprintx($dd) . " survives round_trip");
cmp_ok($dd, '==', dd_nextdown($nu), "down-up " . sprintx($dd) . " survives round_trip");
$second *= -1;
$dd = Math::FakeDD->new($first) + $second;
$nu = dd_nextup($dd);
cmp_ok($nu, '==', Math::FakeDD->new($first) + ($second) + Math::FakeDD::DBL_DENORM_MIN,
"dd_nextup(2**$p1) + (2**$p2)) == (2**$p1) + (2**$p2) + (2 ** -1074)");
cmp_ok($nu - $dd, '==', Math::FakeDD->new(2 ** ulp_exponent($dd)), "$nu - $dd ok");
$nd = dd_nextdown($dd);
cmp_ok($nd, '==', Math::FakeDD->new($first) + ($second) - Math::FakeDD::DBL_DENORM_MIN,
"dd_nextdown(2**$p1) + (2**$p2)) == (2**$p1) + (2**$p2) -(2 ** -1074)");
cmp_ok($dd - $nd, '==', Math::FakeDD->new(2 ** ulp_exponent($dd)), "$dd - $nd ok");
cmp_ok($dd, '==', dd_nextup($nd), "up-down " . sprintx($dd) . " survives round_trip");
cmp_ok($dd, '==', dd_nextdown($nu), "down-up " . sprintx($dd) . " survives round_trip");
$first *= -1;
$dd = Math::FakeDD->new($first) + $second;
$nu = dd_nextup($dd);
cmp_ok($nu, '==', Math::FakeDD->new($first) + ($second) + Math::FakeDD::DBL_DENORM_MIN,
"dd_nextup(2**$p1) + (2**$p2)) == (2**$p1) + (2**$p2) + (2 ** -1074)");
cmp_ok($nu - $dd, '==', Math::FakeDD->new(2 ** ulp_exponent($dd)), "$nu - $dd ok");
$nd = dd_nextdown($dd);
cmp_ok($nd, '==', Math::FakeDD->new($first) + ($second) - Math::FakeDD::DBL_DENORM_MIN,
"dd_nextdown(2**$p1) + (2**$p2)) == (2**$p1) + (2**$p2) -(2 ** -1074)");
cmp_ok($dd - $nd, '==', Math::FakeDD->new(2 ** ulp_exponent($dd)), "$dd - $nd ok");
cmp_ok($dd, '==', dd_nextup($nd), "up-down " . sprintx($dd) . " survives round_trip");
cmp_ok($dd, '==', dd_nextdown($nu), "down-up " . sprintx($dd) . " survives round_trip");
}
###############################################################################################
for(1 .. 100) {
my $p1 = int(rand(1024));
$p1 *= -1 if $_ % 2; # check for equal numbers of -ve and +ve powers
my $p2 = $p1 - int(rand(52));
my $p3 = int(rand(1024));
$p3 *= -1 if $_ % 3;
my $p4 = $p3 - int(rand(52));
my $first = 2 ** $p1;
my $second = 2 ** $p2;
my $third = 2 ** $p3;
my $fourth = 2 ** $p4;
my $dd1 = Math::FakeDD->new($first) + $second;
my $dd2 = Math::FakeDD->new($third) + $fourth;
my $dd = $dd1 + $dd2;
my $nu = dd_nextup($dd);
my $nd = dd_nextdown($dd);
cmp_ok($dd, '==', dd_nextup($nd), "up-down " . sprintx($dd) . " survives round_trip");
cmp_ok($dd, '==', dd_nextdown($nu), "down-up " . sprintx($dd) . " survives round_trip");
$dd1 *= -1;
$dd = $dd1 + $dd2;
$nu = dd_nextup($dd);
$nd = dd_nextdown($dd);
cmp_ok($dd, '==', dd_nextup($nd), "up-down " . sprintx($dd) . " survives round_trip");
cmp_ok($dd, '==', dd_nextdown($nu), "down-up " . sprintx($dd) . " survives round_trip");
$dd2 *= -1;
$dd = $dd1 + $dd2;
$nu = dd_nextup($dd);
$nd = dd_nextdown($dd);
cmp_ok($dd, '==', dd_nextup($nd), "up-down " . sprintx($dd) . " survives round_trip");
cmp_ok($dd, '==', dd_nextdown($nu), "down-up " . sprintx($dd) . " survives round_trip");
$dd1 *= -1;
$dd = $dd1 + $dd2;
$nu = dd_nextup($dd);
$nd = dd_nextdown($dd);
cmp_ok($dd, '==', dd_nextup($nd), "up-down " . sprintx($dd) . " survives round_trip");
cmp_ok($dd, '==', dd_nextdown($nu), "down-up " . sprintx($dd) . " survives round_trip");
}
###############################################################################################
my @ss = ('1' x 53, ('1' x 52) . '0', ('1' x 51) . '00', '1101' . ('1' x 49), '11101' . ('1' x 47) . '0',);
for(@ss) { die "Bad string in \@ss" if length($_) != 53 }
my @sm = ('000', '001', '010', '011', '100', '101', '110', '111',);
for(@sm) { die "Bad string in \@sm" if length($_) != 3 }
my @sf = ('0' . ('1' x 50), '1' x 51, '00'. ('1' x 49),);
for(@sf) { die "Bad string in \@sm" if length($_) != 51 }
my $mpfr = Math::MPFR::Rmpfr_init2(2098);
for(1..200) {
my $start = $ss[int(rand(scalar(@ss)))];
substr($start, 1 + int(rand(53)), 0, '.'); # randomly insert a radix point.
die "starting string is of wrong length" unless length($start) == 54;
my $middle = $sm[int(rand(scalar(@sm)))];
my $finish = $sf[int(rand(scalar(@sf)))];
my $mantissa = $start . $middle . $finish;
my $exp = $_ % 2 ? 'p+' . int(rand(1024))
: 'p-' . int(rand(1075));
my $binstring = $mantissa . $exp;
Math::MPFR::Rmpfr_strtofr($mpfr, $binstring, 2, 0);
my $dd = mpfr2dd($mpfr);
my $nu = dd_nextup($dd);
my $nd = dd_nextdown($dd);
cmp_ok($dd, '==', dd_nextup($nd), "up-down " . sprintx($dd) . " survives round_trip");
unless(dd_is_inf($dd)) { # $dd could be +inf
cmp_ok($dd, '==', dd_nextdown($nu), "down-up " . sprintx($dd) . " survives round_trip");
}
$dd *= -1;
$nu = dd_nextup($dd);
$nd = dd_nextdown($dd);
unless(dd_is_inf($dd)) { # $dd could be -inf
cmp_ok($dd, '==', dd_nextup($nd), "up-down " . sprintx($dd) . " survives round_trip");
}
cmp_ok($dd, '==', dd_nextdown($nu), "down-up " . sprintx($dd) . " survives round_trip");
}
###############################################################################################
@ss = ('1' x 53, ('1' x 52) . '0', ('1' x 51) . '00', '1101' . ('1' x 49), '11101' . ('1' x 47) . '0',);
for(@ss) { die "Bad string in \@ss" if length($_) != 53 }
@sm = ('000', '001', '010', '011', '100', '101', '110', '111',);
for(@sm) { die "Bad string in \@sm" if length($_) != 3 }
@sf = ('0' x 51,);
for(@sf) { die "Bad string in \@sm" if length($_) != 51 }
$mpfr = Math::MPFR::Rmpfr_init2(2098);
for(1..200) {
my $start = $ss[int(rand(scalar(@ss)))];
substr($start, 1 + int(rand(53)), 0, '.'); # randomly insert a radix point.
die "starting string is of wrong length" unless length($start) == 54;
my $middle = $sm[int(rand(scalar(@sm)))];
#my $finish = $sf[int(rand(scalar(@sf)))];
my $finish = $sf[0];
my $mantissa = $start . $middle . $finish;
my $exp = $_ % 2 ? 'p+' . int(rand(1024))
: 'p-' . int(rand(1075));
my $binstring = $mantissa . $exp;
Math::MPFR::Rmpfr_strtofr($mpfr, $binstring, 2, 0);
my $dd = mpfr2dd($mpfr);
my $nu = dd_nextup($dd);
my $nd = dd_nextdown($dd);
unless($dd > 0 && dd_is_inf($dd)) {
cmp_ok($dd, '<', $nu, sprintx($dd) . " < " . sprintx($nu));
cmp_ok($dd, '==', dd_nextdown($nu), "down-up roundtrip for " . sprintx($dd) . "ok" );
}
unless($dd < 0 && dd_is_inf($dd)) {
cmp_ok($dd, '>', $nd, sprintx($dd) . " > " . sprintx($nd));
cmp_ok($dd, '==', dd_nextup($nd), "up-down roundtrip for " . sprintx($dd) . "ok" );
}
$dd *= -1;
$nu = dd_nextup($dd);
$nd = dd_nextdown($dd);
unless($dd < 0 && dd_is_inf($dd)) {
cmp_ok($dd, '==', dd_nextup($nd), "up-down " . sprintx($dd) . " survives round_trip");
}
unless($dd > 0 && dd_is_inf($dd)) {
cmp_ok($dd, '==', dd_nextdown($nu), "down-up " . sprintx($dd) . " survives round_trip");
}
}
## Some specific values that have caused problems:
my @probs = (
[0x1.0010000000002p-796, 0x1p-849],
[0x1p-967, -0x1p-1022],
[-0x1.000003ffffffep-31, 0x1p-96],
[-0x1.000fffffffffep-10, 0x1p-81],
);
for(@probs) {
# Test nextdown(nextup($dd))
my @args = @$_;
$dd = any2dd(@args);
#warn sprintx($dd) . "\n";
$nu = dd_nextup($dd);
cmp_ok($nu, '>', $dd, sprintx($nu) . ' > ' . sprintx($dd));
$rt = dd_nextdown($nu);
cmp_ok($rt, '==', $dd, sprintx($rt) . ' == ' . sprintx($dd));
$dd = any2dd(-$args[0], $args[1]);
$nu = dd_nextup($dd);
cmp_ok($nu, '>', $dd, sprintx($nu) . ' > ' . sprintx($dd));
$rt = dd_nextdown($nu);
cmp_ok($rt, '==', $dd, sprintx($rt) . ' == ' . sprintx($dd));
$dd = any2dd($args[0], -$args[1]);
$nu = dd_nextup($dd);
cmp_ok($nu, '>', $dd, sprintx($nu) . ' > ' . sprintx($dd));
$rt = dd_nextdown($nu);
cmp_ok($rt, '==', $dd, sprintx($rt) . ' == ' . sprintx($dd));
$dd = any2dd(-$args[0], -$args[1]);
$nu = dd_nextup($dd);
cmp_ok($nu, '>', $dd, sprintx($nu) . ' > ' . sprintx($dd));
$rt = dd_nextdown($nu);
cmp_ok($rt, '==', $dd, sprintx($rt) . ' == ' . sprintx($dd));
}
for(@probs) {
# Test nextup(nextdown($dd))
my @args = @$_;
$dd = any2dd(@args);
$nd = dd_nextdown($dd);
cmp_ok($nd, '<', $dd, sprintx($nd) . ' < ' . sprintx($dd));
$rt = dd_nextup($nd);
cmp_ok($rt, '==', $dd, sprintx($rt) . ' == ' . sprintx($dd));
$dd = any2dd(-$args[0], $args[1]);
$nd = dd_nextdown($dd);
cmp_ok($nd, '<', $dd, sprintx($nd) . ' < ' . sprintx($dd));
$rt = dd_nextup($nd);
cmp_ok($rt, '==', $dd, sprintx($rt) . ' == ' . sprintx($dd));
$dd = any2dd($args[0], -$args[1]);
$nd = dd_nextdown($dd);
cmp_ok($nd, '<', $dd, sprintx($nd) . ' < ' . sprintx($dd));
$rt = dd_nextup($nd);
cmp_ok($rt, '==', $dd, sprintx($rt) . ' == ' . sprintx($dd));
$dd = any2dd(-$args[0], -$args[1]);
$nd = dd_nextdown($dd);
cmp_ok($nd, '<', $dd, sprintx($nd) . ' < ' . sprintx($dd));
$rt = dd_nextup($nd);
cmp_ok($rt, '==', $dd, sprintx($rt) . ' == ' . sprintx($dd));
}
#################
done_testing(); #
#################