【问题标题】:Rounding towards zero on a PDL在 PDL 上向零舍入
【发布时间】:2017-11-22 21:56:12
【问题描述】:

我有一个混合值(正数和负数)的 PDL(类型 double)。我想将每个条目四舍五入为零。 所以+1.2变成+1+1.7变成+1-1.2变成-1-1.7变成-1

我曾想过使用int(),但它不适用于 PDL 类型。

我也可以使用round(abs($x) - 0.5) * ($x <=> 0),但不确定如何在 PDL 上使用此逻辑。

指针?

【问题讨论】:

    标签: perl rounding pdl


    【解决方案1】:

    PDL::Mathrint 函数的文档说:

    如果您想将半整数从零四舍五入,请尝试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]
    ]
    

    【讨论】:

    • @KoshVery:已更新,这与旧版本的代码有关。
    【解决方案2】:

    PDL::Math 具有 floorceilrint。所有这些功能都可以正常工作。

    因此,应该可以使用以下方法:

    #!/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 变量是$myPDL,我将如何使用abs()&lt;=&gt;$x 是否会改为 $myPdl,而该函数会自动应用于 PDL 中的每个条目?
    • 条件($x &gt;= 0)$x是一个单独的变量。如何检查 PDL 中的每个条目,然后选择 floor()ceil()
    • 语句是否应该是($myPdl &gt;= 0) ? floor($myPdl) : ceil($myPdl); 并且它将对所有条目都执行此操作?
    • @choroba floor() 不会向 零舍入。将失败,例如,-12.2
    • @CinCout:这就是为什么会有abs。查看我的回复。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-02-05
    • 1970-01-01
    • 1970-01-01
    • 2021-01-07
    • 1970-01-01
    • 2017-09-02
    相关资源
    最近更新 更多