Добро пожаловать в форум, Guest  >>   Войти | Регистрация | Поиск | Правила | В избранное | Подписаться
Все форумы / Microsoft SQL Server Новый топик    Ответить
 Сдвиг бит и переполнение типа bigint  [new]
lex452
Member

Откуда:
Сообщений: 574
есть необходимость сдвинуть число на 12 бит влево и получить результат в bigint
declare @NUM bigint=39877
--сдвигаем
select @NUM=@NUM*0x1000000000000

в калькуляторе все получается так как нужно (-7 222 366 427 418 722 304),
что входит в диапазон bigint от -2^63 (-9 223 372 036 854 775 808) до 2^63-1 (9 223 372 036 854 775 807)
и полученное число получается присвоить переменной
declare @NUM bigint=-7222366427418722304


но вот при операции
declare @NUM bigint=39877
select @NUM=@NUM*0x1000000000000

выдает ошибку арифметического переполнения, в чем здесь проблема и как ее решить?
17 апр 17, 10:50    [20406892]     Ответить | Цитировать Сообщить модератору
 Re: Сдвиг бит и переполнение типа bigint  [new]
Владислав Колосов
Member

Откуда:
Сообщений: 7868
lex452,

калькулятор Вас обманывает - он показывает переполнение как знак "минус".
17 апр 17, 10:59    [20406929]     Ответить | Цитировать Сообщить модератору
 Re: Сдвиг бит и переполнение типа bigint  [new]
aleks2
Guest
lex452
есть необходимость сдвинуть число на 12 бит влево и получить результат в bigint
declare @NUM bigint=39877
--сдвигаем
select @NUM=@NUM*0x1000000000000

в калькуляторе все получается так как нужно (-7 222 366 427 418 722 304),
что входит в диапазон bigint от -2^63 (-9 223 372 036 854 775 808) до 2^63-1 (9 223 372 036 854 775 807)
и полученное число получается присвоить переменной
declare @NUM bigint=-7222366427418722304


но вот при операции
declare @NUM bigint=39877
select @NUM=@NUM*0x1000000000000

выдает ошибку арифметического переполнения, в чем здесь проблема и как ее решить?


Ну дык, сдвиньте на 1, потом на 2, потом ... и до вас дойдет.

ЗЫ. Бит знака числа в целых числах со знаком рассматривается особо. А беззнакового biguint - нема.
17 апр 17, 11:00    [20406931]     Ответить | Цитировать Сообщить модератору
 Re: Сдвиг бит и переполнение типа bigint  [new]
iap
Member

Откуда: Москва
Сообщений: 47001
0x1000000000000 - это сколько, по-вашему?

Это 1612
Приблизительно 210=103
Поэтому (24)12=248 - это приблизительно 1015
Умножаем на 39877 (приблизительно 4*104) - получаем примерно 1019

Это то, что вы хотели?!

В то же время, чтобы сдвинуть на 12 бит, надо умножить всего лишь на 212
17 апр 17, 11:16    [20406987]     Ответить | Цитировать Сообщить модератору
 Re: Сдвиг бит и переполнение типа bigint  [new]
AR®
Member

Откуда: Подмосковье
Сообщений: 330
Разве сдвиг на 12 бит влево - это не умножение на 2^12 = 4096 = 0x1000?
17 апр 17, 11:21    [20407007]     Ответить | Цитировать Сообщить модератору
 Re: Сдвиг бит и переполнение типа bigint  [new]
Владислав Колосов
Member

Откуда:
Сообщений: 7868
Это двойка, умноженная на результат предыдущего умножения, а не на саму себя.
17 апр 17, 11:30    [20407041]     Ответить | Цитировать Сообщить модератору
 Re: Сдвиг бит и переполнение типа bigint  [new]
iap
Member

Откуда: Москва
Сообщений: 47001
AR®
Разве сдвиг на 12 бит влево - это не умножение на 2^12 = 4096 = 0x1000?
Но в первом посте написано 0x1000000000000
17 апр 17, 11:32    [20407048]     Ответить | Цитировать Сообщить модератору
 Re: Сдвиг бит и переполнение типа bigint  [new]
AR®
Member

Откуда: Подмосковье
Сообщений: 330
iap
Но в первом посте написано 0x1000000000000

Очевидно, что автор ошибся, написав "0x", а подразумевая "0b".
17 апр 17, 11:35    [20407056]     Ответить | Цитировать Сообщить модератору
 Re: Сдвиг бит и переполнение типа bigint  [new]
iap
Member

Откуда: Москва
Сообщений: 47001
AR®
iap
Но в первом посте написано 0x1000000000000

Очевидно, что автор ошибся, написав "0x", а подразумевая "0b".
Нет никакого 0b в Transact SQL!
Но зато есть Book On Line!
17 апр 17, 11:37    [20407067]     Ответить | Цитировать Сообщить модератору
 Re: Сдвиг бит и переполнение типа bigint  [new]
lex452
Member

Откуда:
Сообщений: 574
Что-то я не понял, решение у моей задачи есть или нет, число же в итоге получается удовлетворяющее bigint, почему переполнение происходит?
17 апр 17, 11:38    [20407069]     Ответить | Цитировать Сообщить модератору
 Re: Сдвиг бит и переполнение типа bigint  [new]
iap
Member

Откуда: Москва
Сообщений: 47001
lex452
Что-то я не понял, решение у моей задачи есть или нет, число же в итоге получается удовлетворяющее bigint, почему переполнение происходит?
Что непонятного?
Надо сдвинуть на 12 бит, а сдвигаете на 48.
17 апр 17, 11:43    [20407092]     Ответить | Цитировать Сообщить модератору
 Re: Сдвиг бит и переполнение типа bigint  [new]
lex452
Member

Откуда:
Сообщений: 574
извините глупца, мне надо на 48 сдвинуть, это я просто запутался сам
17 апр 17, 11:48    [20407114]     Ответить | Цитировать Сообщить модератору
 Re: Сдвиг бит и переполнение типа bigint  [new]
rnk
Member

Откуда:
Сообщений: 126
create function dbo.fn_CareMult(
    @x bigint,
    @y bigint
) returns bigint
as
begin
    declare @result decimal(38,0) = 1;
    set @result = @result * @x * @y;
    if @result > 18446744073709551615 set @result = NULL;-- Переполнение
    if @result between 9223372036854775808 and 18446744073709551615 set @result = @result - 18446744073709551616;
    return convert(bigint,@result);
end;
GO

select dbo.fn_CareMult(0x1000000000000,39877)
-- -7222366427418722304
17 апр 17, 12:19    [20407214]     Ответить | Цитировать Сообщить модератору
 Re: Сдвиг бит и переполнение типа bigint  [new]
lex452
Member

Откуда:
Сообщений: 574
rnk
create function dbo.fn_CareMult(
    @x bigint,
    @y bigint
) returns bigint
as
begin
    declare @result decimal(38,0) = 1;
    set @result = @result * @x * @y;
    if @result > 18446744073709551615 set @result = NULL;-- Переполнение
    if @result between 9223372036854775808 and 18446744073709551615 set @result = @result - 18446744073709551616;
    return convert(bigint,@result);
end;
GO

select dbo.fn_CareMult(0x1000000000000,39877)
-- -7222366427418722304

Это то что нужно, что-то я не додумался использовать тип больше 8 байт для временной переменной
17 апр 17, 12:34    [20407261]     Ответить | Цитировать Сообщить модератору
 Re: Сдвиг бит и переполнение типа bigint  [new]
rnk
Member

Откуда:
Сообщений: 126
Так будет точнее:
create function dbo.fn_CareMult(
    @x bigint,
    @y bigint
) returns bigint
as
begin
    declare @result decimal(38,0) = 1;
    set @result = @result * @x * @y;
    if @result > 18446744073709551615 set @result = NULL;-- Переполнение
    if @result < -18446744073709551616 set @result = NULL;-- Отрицательное переполнение
    if @result between 9223372036854775808 and 18446744073709551615 set @result = @result - 18446744073709551616;
    return convert(bigint,@result);
end;
GO

select dbo.fn_CareMult(0x1000000000000,39877)
-- -7222366427418722304
17 апр 17, 14:08    [20407702]     Ответить | Цитировать Сообщить модератору
 Re: Сдвиг бит и переполнение типа bigint  [new]
AR®
Member

Откуда: Подмосковье
Сообщений: 330
iap
Нет никакого 0b в Transact SQL!


А я и не говорил, что есть (спасибо хоть, вроде в C# собирались "вернуть"). :)
Я лишь говорил, что автор подразумевал не то, что написал.
17 апр 17, 14:42    [20407850]     Ответить | Цитировать Сообщить модератору
Все форумы / Microsoft SQL Server Ответить