Округление до нуля на 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.

Указатели?

2 ответа

Решение

Документация rint функция в PDL:: Math говорит:

Если вы хотите округлить половину целых чисел от нуля, попробуйте 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:: Математика 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, кажется, работает примерно на 20% быстрее в следующем тесте с непотоковым perl 5.24 на древнем MacBook Pro:

#!/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;
Другие вопросы по тегам