Как конвертировать последние 3 цифры числа в 0

Как преобразовать последние 3 цифры числа в 0

пример 3444678 - 3444000

Я могу сделать как

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

Но деление и умножение могут быть дорогостоящими...

Любое другое решение????

Ответ 1

Вы можете попробовать

n - (n % 1000)

но оператор модуля может быть столь же дорогостоящим, как и деление. В любом случае это звучит очень много, как микро-оптимизация. Это действительно ваше узкое место?

Ответ 2

Смещение трюка, затем:

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

Это быстрее? Сомнительно.

Но вот забавный факт: gcc не использует для этого раздел/модуль:

n -= n % 1000;

Он умножается на какое-то безумное число (274877907) и делает некоторые другие вещи, которые предположительно быстрей.

Мораль этой истории: чем более очевидна цель вашего кода для компилятора, тем больше вероятность того, что компилятор будет оптимизировать его так, как вы никогда не задумывались. Если код легче понять людям, это еще один бонус.

Ответ 3

Так же, как, кстати, (здесь вы уже получили хороший вклад).

Бит-манипуляция никогда не работает с десятичными числами. Проблема в том, что значения битов вообще не отображаются на десятичные. С BCD он отлично работает, но никто никогда не использует его (может быть, BigDecimal делает, я в этом сомневаюсь).

В любом случае, один базовый трюк, который вы можете использовать, умножается на 10, но он никогда не стоит, если вы не кодируете сборку на каком-то 1970-м процессоре; но только потому, что он загрязняет мои банки памяти, я отправлю его для вашего удовольствия:

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, но я не собираюсь это выяснять - поздно. Если я правильно помню, это имеет какое-то отношение к рассмотрению смещенных битов и добавляя значения обратно в зависимости от их значения.

Ответ 4

Если вы работаете над восьмерикой, вы можете просто:

x &= ~0777;

Если вы работаете с hex, вы можете просто:

x &= ~0xfff;

Но для десятичного числа вы должны, вероятно, сделать это так, как предлагает Джесси Бедер:

x -= (x % 1000);

Большинство систем имеют быстрое целочисленное деление; если вы работаете над системой, которая этого не делает, вы можете использовать алгоритм double dabble для быстрого преобразования в bcd. Посмотрите на раздел о делении на десять.

В зависимости от того, что еще вы пытаетесь сделать, может быть проще обрезать при преобразовании числа в формат печати (строки), предложенный Авитусом.

Ответ 5

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, затем addZeroes. Не может быть проще!

У меня возникло соблазн добавить в int temp = num, а затем использовать его, но полагал, что это будет слишком много, даже для этого кода.

Ответ 6

Если вы хотите округлить до произвольной точности, а ваш круглый метод не имеет контроля точности, это должно работать:

В 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. Я не мог использовать float 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 )

с использованием метода модуля

Это работает, как указано выше (кроме без округления), используя метод модуля для int, но все же работает для округления в точность float (с небольшим замедлением для исправлений справа от десятичной точки.

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 )