如何将数字的后3位数转换为0

时间:2008-11-14 01:06:49

标签: optimization math

如何将数字的最后3位数字转换为0

示例3444678至3444000

我可以这样做

(int)(3444678/1000)* 1000 = 3444000

但是划分和乘法可能代价高昂......

任何其他解决方案????

6 个答案:

答案 0 :(得分:11)

你可以尝试

n - (n % 1000)

但模数运算符可能与分区一样昂贵。无论如何,这听起来很像微优化。这真的是你的瓶颈吗?

答案 1 :(得分:5)

转换技巧,然后:

n >>= 3;
n -= n % (5 * 5 * 5);
n <<= 3;

更快吗?值得怀疑的。

但这是一个有趣的事实:gcc不使用除法/模数:

n -= n % 1000;

它乘以一些疯狂的数字(274877907)并做一些其他可能更快的东西。

这个故事的寓意:代码对编译器的目的越明显,编译器就越有可能以你从未想到的方式对其进行优化。如果代码更易于人类理解,那就是另一个奖励。

答案 2 :(得分:1)

顺便说一下(你已经在这里得到了很好的意见)。

位操作永远不会与十进制数一起使用。问题是这些位的值根本不映射到十进制。使用BCD它可以很好地工作,但没有人使用它(也许BigDecimal会这样做但我对此表示怀疑)。

无论如何,你可以使用的一个基础10技巧是乘以10的因子,但除非你在某些1970年代的CPU上编写汇编,否则它永远不值得。但只是因为它污染了我的记忆库,我会发布它以供你娱乐:

int mult10(int val) {
    int tmp_2val = val << 1; // double val
    int tmp_8val = val << 3; // 8x val
    return( tmp_2val + tmp_8val ); // 2x + 8x = 10x
}

但数学协处理器可以比这快得多,只是从不优化!您甚至考虑执行速度这一事实是一个问题,而您的“优化”通常可能会使系统速度降低而不是加快速度。

我相信你可以使用类似的方法除以10,但我不会试图弄明白 - 它已经很晚了 - 如果我没记错的话,它与检查移出的位有关根据价值重新加入值。

答案 3 :(得分:1)

如果您正在处理八进制,您可以简单地:

x &= ~0777;

如果你正在使用十六进制,你可以简单地说:

x &= ~0xfff;

但是对于十进制,你应该像Jesse Beder建议的那样做:

x -= (x % 1000);

大多数系统都有快速整数除法;如果你正在处理一个没有的系统,你可以使用double dabble算法快速转换为bcd。请看有关除以十的部分。

根据您尝试做的其他事情,将数字转换为Avitus建议的可打印(字符串)格式时可能更容易截断。

答案 4 :(得分:0)

int takeAway(int num)
{
    for (int i = 1; i =< 3; i++)
    {
        num = num/10;
    }

    return num;
}

int addZeroes(int num)
{
    for (int i = 1; i =< 3; i++)
    {
        num = num*10;
    }

    return num;
}

然后你只需要调用takeAway然后添加零。不可能更简单!

我很想添加一个 int temp = num ,然后使用它,但是想的太多了,即使对于这段代码也是如此。

答案 5 :(得分:0)

如果你想要舍入到任意精度而你的圆形方法缺乏精确控制,那么这应该有效:

至少在Perl中,mod应该更快

为什么: (10 ** 7)* 3个随机浮点样本产生了这个基准:

Dividing
Time taken was  7 wallclock secs ( 6.83 usr  0.00 sys +  0.00 cusr  0.00 csys =  6.83 CPU) seconds

Multiplying
Time taken was  7 wallclock secs ( 6.67 usr  0.00 sys +  0.00 cusr  0.00 csys =  6.67 CPU) seconds

Modding
Time taken was  8 wallclock secs ( 7.87 usr  0.00 sys +  0.00 cusr  0.00 csys =  7.87 CPU) seconds

Multiply + Dividing
Time taken was 10 wallclock secs (10.18 usr  0.01 sys +  0.00 cusr  0.00 csys = 10.19 CPU) seconds

请注意,10 ** 7 * 3 REDICULOUS 浮点数。我无法使用10**8浮点数,因为为了公平的测试,我必须对所有测试使用相同的浮点序列,并且许多浮点数排出我的4G内存

好的,位侧话题:/

(Perl实现仅使用Int,它截断而不是正常舍入)

use strict;
use warnings;
use version;
our $VERSION = qv('0.1');

sub xround { 
    my ( $number, $precision ) = @_ ;
    if ( $precision eq 0 )
    {
        return int( $number + .5 ); 
    }
    my $scale = 10 ** abs( $precision ) ;

    $number = $number / $scale if $precision > 0; 
    $number = $number * $scale if $precision < 0; 

    $number = int( $number + .5 );

    $number = $number * $scale if $precision > 0; 
    $number = $number / $scale if $precision < 0; 
    return $number;
}

my $fmt = "%s : %s  ( %s )\n";
my $n = 55555.55555;
for my $i ( -4 .. 4 )
{

    printf $fmt, $n, xround($n, $i), $i; 
}

55555.55555 : 55555.5556  ( -4 )
55555.55555 : 55555.556  ( -3 )
55555.55555 : 55555.56  ( -2 )
55555.55555 : 55555.6  ( -1 )
55555.55555 : 55556  ( 0 )
55555.55555 : 55560  ( 1 )
55555.55555 : 55600  ( 2 )
55555.55555 : 56000  ( 3 )
55555.55555 : 60000  ( 4 )

使用模数法

如上所述,(除了不进行舍入)使用模数法进行整数,但仍可用于舍入为浮点精度(对于小数点右侧的精度稍微减慢一点。

use strict;
use warnings;
use version;
our $VERSION = qv('0.1');

sub xround {
    my ( $number, $precision ) = @_;
    my $ino = int( $number );
    if ( $precision eq 0 ) {
        return $ino; 
    }
    my $power = 10**$precision;

    if ( $precision > 0 ) {
        return int( $number - ( $number % $power ) );
    }
    return $ino + int( ( $number - $ino ) / $power ) * $power;
}


my $fmt = "%s : %s  ( %s )\n";
my $n = 55555.55555;
for my $i ( -4 .. 4 )
{
    printf $fmt, $n, xround($n, $i), $i; 
}

55555.55555 : 55555.5555  ( -4 )
55555.55555 : 55555.555  ( -3 )
55555.55555 : 55555.55  ( -2 )
55555.55555 : 55555.5  ( -1 )
55555.55555 : 55555  ( 0 )
55555.55555 : 55550  ( 1 )
55555.55555 : 55500  ( 2 )
55555.55555 : 55000  ( 3 )
55555.55555 : 50000  ( 4 )