在 PDL 上向零舍入
Rounding towards zero on a PDL
我有一个混合值(正值和负值)的 PDL(类型 double
)。我想将每个条目四舍五入为零。
所以+1.2
变成+1
,+1.7
变成+1
,-1.2
变成-1
,-1.7
变成-1
,
我考虑过使用 int()
,但它不适用于 PDL 类型。
我也可以使用 round(abs($x) - 0.5) * ($x <=> 0)
,但不确定如何在 PDL 上使用此逻辑。
指针?
PDL::Math 有 floor
、ceil
和 rint
。所有这些功能都可以正常工作。
因此,像下面这样的东西应该可以工作:
#!/usr/bin/env perl
use warnings;
use strict;
use PDL;
my $pdl = 'PDL'->new(
[ 1, 1.3, 1.9, 2, 2.1, 2.7 ],
[ -1, -1.3, -1.9, -2, -2.1, -2.7 ]
);
print $pdl;
floor(inplace $pdl->where($pdl >= 0));
ceil (inplace $pdl->where($pdl < 0));
print $pdl;
输出:
[
[ 1 1.3 1.9 2 2.1 2.7]
[ -1 -1.3 -1.9 -2 -2.1 -2.7]
]
[
[ 1 1 1 2 2 2]
[-1 -1 -1 -2 -2 -2]
]
PS:@choroba 的回答在 an ancient MacBook Pro 上使用非线程 perl
5.24 的以下基准测试中似乎 运行 快了大约 20%:
#!/usr/bin/env perl
use warnings;
use strict;
use constant N_ELEMS => $ARGV[0] || 100_000;
use Dumbbench;
use PDL;
sub one_scan {
my $pdl = 100 * grandom(N_ELEMS);
$pdl = floor(abs($pdl)) * ($pdl <=> 0);
return;
}
sub two_scans {
my $pdl = 100 * grandom(N_ELEMS);
floor(inplace $pdl->where($pdl >= 0));
ceil (inplace $pdl->where($pdl < 0));
return;
}
sub baseline {
my $pdl = 100 * grandom(N_ELEMS);
return;
}
my $bench = Dumbbench->new;
$bench->add_instances(
Dumbbench::Instance::PerlSub->new(code => \&baseline, name => 'Baseline'),
Dumbbench::Instance::PerlSub->new(code => \&one_scan, name => 'One Scan'),
Dumbbench::Instance::PerlSub->new(code => \&two_scans, name => 'Two Scans'),
);
$bench->run;
$bench->report;
PDL::Math 中 rint
函数的文档说:
If you want to round half-integers away from zero, try floor(abs($x)+0.5)*($x<=>0)
.
只需稍作更改即可使其按您想要的方式工作:
#!/usr/bin/perl
use warnings;
use strict;
use PDL;
my $pdl = 'PDL'->new(
[ 1, 1.3, 1.9, 2, 2.1, 2.7 ],
[ -1, -1.3, -1.9, -2, -2.1, -2.7 ]
);
$pdl = floor(abs($pdl)) * ($pdl <=> 0);
print $pdl;
输出:
[
[ 1 1 1 2 2 2]
[-1 -1 -1 -2 -2 -2]
]
我有一个混合值(正值和负值)的 PDL(类型 double
)。我想将每个条目四舍五入为零。
所以+1.2
变成+1
,+1.7
变成+1
,-1.2
变成-1
,-1.7
变成-1
,
我考虑过使用 int()
,但它不适用于 PDL 类型。
我也可以使用 round(abs($x) - 0.5) * ($x <=> 0)
,但不确定如何在 PDL 上使用此逻辑。
指针?
PDL::Math 有 floor
、ceil
和 rint
。所有这些功能都可以正常工作。
因此,像下面这样的东西应该可以工作:
#!/usr/bin/env perl
use warnings;
use strict;
use PDL;
my $pdl = 'PDL'->new(
[ 1, 1.3, 1.9, 2, 2.1, 2.7 ],
[ -1, -1.3, -1.9, -2, -2.1, -2.7 ]
);
print $pdl;
floor(inplace $pdl->where($pdl >= 0));
ceil (inplace $pdl->where($pdl < 0));
print $pdl;
输出:
[
[ 1 1.3 1.9 2 2.1 2.7]
[ -1 -1.3 -1.9 -2 -2.1 -2.7]
]
[
[ 1 1 1 2 2 2]
[-1 -1 -1 -2 -2 -2]
]
PS:@choroba 的回答在 an ancient MacBook Pro 上使用非线程 perl
5.24 的以下基准测试中似乎 运行 快了大约 20%:
#!/usr/bin/env perl
use warnings;
use strict;
use constant N_ELEMS => $ARGV[0] || 100_000;
use Dumbbench;
use PDL;
sub one_scan {
my $pdl = 100 * grandom(N_ELEMS);
$pdl = floor(abs($pdl)) * ($pdl <=> 0);
return;
}
sub two_scans {
my $pdl = 100 * grandom(N_ELEMS);
floor(inplace $pdl->where($pdl >= 0));
ceil (inplace $pdl->where($pdl < 0));
return;
}
sub baseline {
my $pdl = 100 * grandom(N_ELEMS);
return;
}
my $bench = Dumbbench->new;
$bench->add_instances(
Dumbbench::Instance::PerlSub->new(code => \&baseline, name => 'Baseline'),
Dumbbench::Instance::PerlSub->new(code => \&one_scan, name => 'One Scan'),
Dumbbench::Instance::PerlSub->new(code => \&two_scans, name => 'Two Scans'),
);
$bench->run;
$bench->report;
PDL::Math 中 rint
函数的文档说:
If you want to round half-integers away from zero, try
floor(abs($x)+0.5)*($x<=>0)
.
只需稍作更改即可使其按您想要的方式工作:
#!/usr/bin/perl
use warnings;
use strict;
use PDL;
my $pdl = 'PDL'->new(
[ 1, 1.3, 1.9, 2, 2.1, 2.7 ],
[ -1, -1.3, -1.9, -2, -2.1, -2.7 ]
);
$pdl = floor(abs($pdl)) * ($pdl <=> 0);
print $pdl;
输出:
[
[ 1 1 1 2 2 2]
[-1 -1 -1 -2 -2 -2]
]