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

Откуда:
Сообщений: 3
Необходимо написать функцию округления к большему.
Например:
UpperRound(12.111, 2) -> 12.12
UpperRound(12.114, 2) -> 12.12
UpperRound(12.119, 2) -> 12.12

отличие от математического округления
Round(12.111, 2) -> 12.11
Round(12.114, 2) -> 12.11
Round(12.119, 2) -> 12.12

----------------------------------------------------------
Примечание: С Sql Server работаю с 3 недели, Oracle более знаком

Помогите переписать вот эту функцию \/
В SQL Server функция Power не возводит число в отрицательную степень кажись...
----------------------------------------------------------
create or replace function UpperRound(Val float, Pow float) return float is
rVal float;
begin
rVal:= round(Val,Pow);
if(rVal<Val) then rVal:= round(Val+Power(10,-1*Pow),Pow); end if;
return(rVal);
end UpperRound;

----------------------------------------------------------
create FUNCTION UpperRound
( @Val numeric(38,16)
, @Pow int
)
RETURNS numeric(38,16)
AS
BEGIN
declare @rVal numeric(38,16)

set @rVal = ROUND(@Val, @Pow)

if @rVal<@Val
set @rVal = ROUND(@Val + POWER(10,-1*@Pow), @Pow)

RETURN (@rVal)
END
14 июл 09, 14:39    [7413642]     Ответить | Цитировать Сообщить модератору
 Re: Округление к большему (Rounding Up)  [new]
Козьма Прутков
Member

Откуда: Москва
Сообщений: 186
Вадим_Вадим, а BOL ваше "кажись" не подтверждает. Зато про тип, возвращаемый power, написано "Same as numeric_expression."
Немножко упростим, убрав одно ненужное округление, и получим ответ:
set @rVal = @rVal + POWER(convert(numeric(38,16), 10),-1*@Pow)
14 июл 09, 14:48    [7413705]     Ответить | Цитировать Сообщить модератору
 Re: Округление к большему (Rounding Up)  [new]
так наверна
Guest
create FUNCTION UpperRound
( @Val numeric(38,16)
, @Pow int
)
RETURNS numeric(38,16)
AS
BEGIN
RETURN CEILING(@Val * POWER(10, @Pow))/POWER(10, @Pow) 
END
14 июл 09, 14:51    [7413717]     Ответить | Цитировать Сообщить модератору
 Re: Округление к большему (Rounding Up)  [new]
vov@
Member

Откуда: Днепропетровск
Сообщений: 110
SELECT ROUND(150.763,2)
SELECT ROUND(150.767,2)

select ROUND((150.763 + (5.00/POWER(10,(2+1)))),2)
select ROUND((150.767 + (5.00/POWER(10,(2+1)))),2)
14 июл 09, 14:52    [7413728]     Ответить | Цитировать Сообщить модератору
 Re: Округление к большему (Rounding Up)  [new]
iap
Member

Откуда: Москва
Сообщений: 46975
Первое, что пришло в голову:
SELECT ROUND(12.111*POWER(10,2)+1,0,1)/POWER(10,2)
14 июл 09, 14:54    [7413751]     Ответить | Цитировать Сообщить модератору
 Re: Округление к большему (Rounding Up)  [new]
iap
Member

Откуда: Москва
Сообщений: 46975
Второе, что пришло в голову:
DECLARE @F FLOAT, @Round INT;
SELECT @F=12.111, @Round=2;

SELECT ROUND(@F+1./POWER(10,@Round),@Round,1);
14 июл 09, 15:26    [7414029]     Ответить | Цитировать Сообщить модератору
 Re: Округление к большему (Rounding Up)  [new]
qwerty112
Guest
iap
Второе, что пришло в голову:
DECLARE @F FLOAT, @Round INT;
SELECT @F=12.111, @Round=2;

SELECT ROUND(@F+1./POWER(10,@Round),@Round,1);


...попробуйте вот это
DECLARE @F FLOAT, @Round INT;
SELECT @F=0, @Round=2;

SELECT ROUND(@F+1./POWER(10,@Round),@Round,1);
14 июл 09, 15:32    [7414069]     Ответить | Цитировать Сообщить модератору
 Re: Округление к большему (Rounding Up)  [new]
vov@
Member

Откуда: Днепропетровск
Сообщений: 110
в моём скрипте есть неточность...нужно вместо 5 поставить 4.9

вот функция
alter FUNCTION UpperRound(@Val numeric(38,16), @Pow int)
RETURNS numeric(38,16)
AS
BEGIN	
	RETURN ROUND((@Val + (4.9/POWER(10,(@Pow+1)))),@Pow)
END
14 июл 09, 15:45    [7414163]     Ответить | Цитировать Сообщить модератору
 Re: Округление к большему (Rounding Up)  [new]
Вадим_Вадим
Member

Откуда:
Сообщений: 3
vov@
в моём скрипте есть неточность...нужно вместо 5 поставить 4.9

С коэффициентом 5.00 не проходит, например
select ROUND((0 + (5.00/POWER(10,(2+1)))),2) = 0.01

С коэффициентом не проходит, например
select ROUND((0.99008 + (4.9/POWER(10,(2+1)))),2) = 0.99

Без глюков(вроде) и наиболее коротко:

[quot iap]Первое, что пришло в голову:
SELECT ROUND(12.111*POWER(10,2)+1,0,1)/POWER(10,2)
14 июл 09, 15:59    [7414272]     Ответить | Цитировать Сообщить модератору
 Re: Округление к большему (Rounding Up)  [new]
Вадим_Вадим
Member

Откуда:
Сообщений: 3
Вот (Guest оставил), самое подходящее:

CEILING(@Val * POWER(10, @Pow))/POWER(10, @Pow)

Всем спасибо...
14 июл 09, 16:05    [7414334]     Ответить | Цитировать Сообщить модератору
 Re: Округление к большему (Rounding Up)  [new]
Козьма Прутков
Member

Откуда: Москва
Сообщений: 186
Вадим_Вадим, будьте аккуратнее с выбранным вариантом: он несет риск переполнения. Я чуть откорректировал, чтобы на несущественное переполнение int'а не ругалось, вот пример:
declare @pow int
declare @val numeric(38, 16)

-- целая часть 22, дробная - 16 разрядов. Предельный случай.
select @val = 1234567890123456789012.1234567890123456
select @pow = 16

-- тут целая часть может содержать максимум 22 - @pow разрядов.
declare @ten numeric(38, 16)
select @ten = 10
select CEILING(@Val * POWER(@ten, @Pow))/POWER(@ten, @Pow)

-- тут все равно.
select ROUND(@Val, @Pow) + case when ROUND(@Val, @Pow) < @val then POWER(convert(numeric(38, 16), 10), -1 * @Pow) else 0 end

Первый по наблюдениям еще и не понимает @pow больше 6, почему-то округляет не далее чем 6 знаков.

Думайте: вам потом ошибки разгребать :)
14 июл 09, 16:43    [7414654]     Ответить | Цитировать Сообщить модератору
 Re: Округление к большему (Rounding Up)  [new]
Ennor Tiegael
Member

Откуда:
Сообщений: 3196
Козьма Прутков,

В любом случае POWER() приводит все свои аргументы, равно как и возвращаемый результат, к float, а следовательно добиться с ней точности более 16 знаков в принципе невозможно...
14 июл 09, 16:52    [7414779]     Ответить | Цитировать Сообщить модератору
 Re: Округление к большему (Rounding Up)  [new]
iap
Member

Откуда: Москва
Сообщений: 46975
Ennor Tiegael
Козьма Прутков,

В любом случае POWER() приводит все свои аргументы, равно как и возвращаемый результат, к float, а следовательно добиться с ней точности более 16 знаков в принципе невозможно...
Ошибаетесь
+ BOL
Синтаксис
POWER ( float_expression , y )
Аргументы
float_expression
Выражение типа float или типа, который может быть неявно преобразован в тип float.
y
Степень, в которую возводится аргумент float_expression. Аргумент y является выражением категории точного числового или приблизительного числового типа данных, за исключением типа данных bit.
Типы возвращаемых данных
То же, что и аргумент float_expression.
14 июл 09, 17:08    [7414982]     Ответить | Цитировать Сообщить модератору
 Re: Округление к большему (Rounding Up)  [new]
Алексей2003
Member

Откуда: Москва
Сообщений: 5645
для тех, кто математику в школе не проходил:
CREATE FUNCTION dbo.upperRound 
	(@val float, 
	 @pow int)
RETURNS float
AS
BEGIN
	return round(@val + 0.5 * power(0.1, @pow), @pow)
END

для спящего время бодрствования равносильно сну
14 июл 09, 17:20    [7415120]     Ответить | Цитировать Сообщить модератору
 Re: Округление к большему (Rounding Up)  [new]
iap
Member

Откуда: Москва
Сообщений: 46975
Алексей2003
для тех, кто математику в школе не проходил:
CREATE FUNCTION dbo.upperRound 
	(@val float, 
	 @pow int)
RETURNS float
AS
BEGIN
	return round(@val + 0.5 * power(0.1, @pow), @pow)
END

для спящего время бодрствования равносильно сну
Так по условию задачи надо всегда округлять к большему!
SELECT round(12.111 + 0.5 * power(0.1, 2), 2)
возвращает 12.11, а не 12.12
14 июл 09, 17:30    [7415210]     Ответить | Цитировать Сообщить модератору
 Re: Округление к большему (Rounding Up)  [new]
Козьма Прутков
Member

Откуда: Москва
Сообщений: 186
Алексей2003, тогда уж вот так:
select round(@val + 0.5 / power(10.0, @pow), @pow)
Теоретически то же самое, а на практике - отнюдь.

Но на примере, когда число уже округлено до нужного количества знаков либо меньшего, этот подход работает неверно, добавляя в результат единицу в последний разряд (по который собираемся округлить):
SELECT round(12.111 + 0.5 / power(10.0, 5), 5)

12.11101

------------
Чем сложнее решение задачи, тем больше вероятность, что оно неправильное
14 июл 09, 17:44    [7415308]     Ответить | Цитировать Сообщить модератору
 Re: Округление к большему (Rounding Up)  [new]
Алексей2003
Member

Откуда: Москва
Сообщений: 5645
IF EXISTS (SELECT * 
	   FROM   sysobjects 
	   WHERE  name = N'upperRound')
	DROP FUNCTION upperRound
GO

CREATE FUNCTION dbo.upperRound 
	(@val numeric(38,19), 
	 @pow int)
RETURNS numeric(38,19)
AS
BEGIN
	return round(@val + 0.5 / power(10, @pow), @pow)
END

GO
SELECT dbo.upperRound (12.111, 2)
GO
блин, power с отрицательным умножителем некорректно отрабатывает.

2iap
поэтому и говорю, для тех кто не изучал математику в школе..

для спящего время бодрствования равносильно сну
14 июл 09, 17:44    [7415309]     Ответить | Цитировать Сообщить модератору
 Re: Округление к большему (Rounding Up)  [new]
Алексей2003
Member

Откуда: Москва
Сообщений: 5645
а, есть заведомо более точные числа, тогда так:
CREATE FUNCTION dbo.upperRound 
	(@val numeric(38,19), 
	 @pow int)
RETURNS numeric(38,19)
AS
BEGIN
	return round(@val + (0.5 / power(10, @pow) - 1.0 / power(10, @pow + 1)), @pow)
END

для спящего время бодрствования равносильно сну
14 июл 09, 17:49    [7415338]     Ответить | Цитировать Сообщить модератору
 Re: Округление к большему (Rounding Up)  [new]
Ennor Tiegael
Member

Откуда:
Сообщений: 3196
iap
Ennor Tiegael
Козьма Прутков,

В любом случае POWER() приводит все свои аргументы, равно как и возвращаемый результат, к float, а следовательно добиться с ней точности более 16 знаков в принципе невозможно...
Ошибаетесь
+ BOL
Синтаксис
POWER ( float_expression , y )
Аргументы
float_expression
Выражение типа float или типа, который может быть неявно преобразован в тип float.
y
Степень, в которую возводится аргумент float_expression. Аргумент y является выражением категории точного числового или приблизительного числового типа данных, за исключением типа данных bit.
Типы возвращаемых данных
То же, что и аргумент float_expression.
А помните, недавно была такая интересная тема - Почему SS XE 2005 возвращает 2^62 "немного неточно" ?
Вкратце, что я имел в виду:
declare @n numeric(38,0), @b bigint;
select @n = 2, @b = 2;
select power(@n, 62) as [numeric], power(@b, 62) as [bigint];

numeric                                 bigint
--------------------------------------- --------------------
4611686018427387900                     4611686018427387904
It's ok, it's numeric - but it's a rounded numeric.
14 июл 09, 17:54    [7415383]     Ответить | Цитировать Сообщить модератору
 Re: Округление к большему (Rounding Up)  [new]
Козьма Прутков
Member

Откуда: Москва
Сообщений: 186
- О, а лом распилит?
- Жжж-ззз-дзинь - сказала японская бензопила и сломалась.
- АГА!!!! - обрадовались крепкие сибирские мужики и пошли дальше валить лес топорами
(с) народ

declare @pow int
declare @val numeric(38, 16)

select @val = 12.120010001
select @pow = 5

select round(@val + (0.5 / power(10, @pow) - 1.0 / power(10, @pow + 1)), @pow)

Ждем: 12.12002
Результат: 12.12001

ЗЫ: какая простая на первый взгляд задача, а топик распух уже почти до 20 сообщений :)
14 июл 09, 18:07    [7415472]     Ответить | Цитировать Сообщить модератору
 Re: Округление к большему (Rounding Up)  [new]
Алексей2003
Member

Откуда: Москва
Сообщений: 5645
хорошо, исследование начнем-с:
power(10, 9) у меня максимальное значение, что может принимать power.
return round(@val + (0.5 / power(10, @pow) - 1.0 / power(10, 9)), @pow)
с максимальной точностью 9 знаков после запятой. если больше, тогда power загибается.


для спящего время бодрствования равносильно сну
14 июл 09, 18:16    [7415541]     Ответить | Цитировать Сообщить модератору
 Re: Округление к большему (Rounding Up)  [new]
Сергей Мишин
Member

Откуда:
Сообщений: 376
как вариант:
DECLARE @Val numeric(38,16), @Pow int

SELECT @Val=12.111 , @Pow = 2
--SELECT @Val = 12.120010001, @Pow = 5

SELECT
	@Val
	,round(
		@Val
		+ cast('0.'+ REPLICATE('0',@Pow) + '4' + REPLICATE('9',15-@Pow) AS numeric(38,16))
		,@Pow
		)
14 июл 09, 18:58    [7415735]     Ответить | Цитировать Сообщить модератору
 Re: Округление к большему (Rounding Up)  [new]
Козьма Прутков
Member

Откуда: Москва
Сообщений: 186
на самом деле до завершения варианта с 0.5 осталось самая малость: надо вычесть 1 из самого младшего возможного разряда (аналогичная идея использована у Сергея Мишина в его посте). Максимальная точность - особый случай, его обработаем отдельно, иначе рискуем исказить результат на ней. Вот так уже нормально будет:
declare @pow int
declare @val numeric(38, 16)

select @val = 12.120010001
select @pow = 6

declare @ten numeric(38, 16)
select @ten = 10

select case when @pow >= 16 then @val else round(@val + (0.5 / power(@ten, @pow) - 1.0 / power(@ten, 16)), @pow) end

А что касается максимальной степени 9 - так я уже об этом не раз в этом топике писал, надо чтобы 10-ка была типа, допускающего большие значения, идеально - numeric(38,16), чтобы все в одном размере считать.

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

------------------------------------------
Чем сложнее решение задачи, тем больше вероятность, что оно неправильное
14 июл 09, 22:41    [7416316]     Ответить | Цитировать Сообщить модератору
Все форумы / Microsoft SQL Server Ответить