[firebase-br] Truncar valor Firebird 2.0

Eduardo Jedliczka edujed em gmail.com
Qua Jul 20 08:16:34 -03 2011


O problema deste método é que um double precision TEM valores com mais
de 3 casas decimais. (Mesmo que num select ele comumente exiba apenas
3 casas após a vírgula)

Quem duvidar, faça um teste:

select 15 / cast(7 as double precision)from rdb$database

e depois:

select 15 / cast(7 as double precision)*100000000000 from rdb$database

.....

Portanto, mesmo que visualmente o valor seja um hipotético 1234.456,
ele poderia estar armazenado na memória com uma "pequena" variação, do
tipo:

select cast (12345.4567891234567 as double precision) from rdb$database


portanto fazer um :


select CAST( *valor do tipo double*  /10*10 AS NUMERIC(18,2)) from rdb$database

verá que retornou 1234.46, sendo que o esperado seria 1234.45


Então se alguém  sugerir...

select CAST(CAST( *valor do tipo double* as Numeric(18,3))/10*10 AS
NUMERIC(18,2)) from rdb$database

também irá apresentar o problema, pois será feito o arredondamento
"para cima" nativo do tipo numeric.


Claro que quando realizamos um select com uma constante numérica, o
firebird estará trabalhando com um "Numeric", não com um "Double".
Portanto, para "entender" o problema do Hélio, é preciso usar um cast
no valor para convertê-lo para double.


Portanto, não vejo muitas saídas:

1ª) UDF
2º) procedure do Daniel (eu não cheguei a testar ela, mas "confio" na fonte)
3º) Usar um IIF (se não me engano existe no FB 2.0) e ver se o valor
com cast é "maior" do que o valor double... como este

select iif( cast(cast(* valor do tipo double * as numeric(15,2)) as
double precision) > * valor do tipo double *, -0.01, 0.00) + cast(*
valor do tipo double * as numeric(15,2)) as valor_truncado from
rdb$database


==========================
Eduardo Jedliczka
Apucarana - Pr
==========================




2011/7/19 Fernando Gutierres <fernando em onclicksistemas.com.br>:
> Como o amigo anteriormente disse, basta dividir por 10 e multiplicar por 10.
> Faça o teste
>
> select CAST(3777.725/10*10 AS NUMERIC(18,2)) from rdb$database
>
> 2011/7/19 Tecnobyte Informática <temp2 em tecnobyte.com.br>:
>> Boa tarde
>>
>> Escrevi um procedimento que talvez resolva seu problema:
>>
>> SET TERM ^ ;
>>
>> CREATE OR ALTER PROCEDURE SP_Trunc(FloatValue DOUBLE PRECISION, Decimals
>> SMALLINT)
>> RETURNS(Result DOUBLE PRECISION) AS
>> DECLARE VARIABLE StrValue VARCHAR(50);
>> DECLARE VARIABLE StrInt VARCHAR(50);
>> DECLARE VARIABLE StrFrac VARCHAR(50);
>> DECLARE VARIABLE AfterSep SMALLINT;
>> DECLARE VARIABLE DecCount SMALLINT;
>> BEGIN
>>  IF (FloatValue IS NULL) THEN
>>   Result = NULL;
>>  ELSE
>>  BEGIN
>>   StrValue = FloatValue;
>>   StrInt = '';
>>   StrFrac = '';
>>   AfterSep = 0;
>>   DecCount = 0;
>>   WHILE (StrValue <> '') DO
>>   BEGIN
>>     IF (SUBSTRING(StrValue FROM 1 FOR 1) = '.') THEN
>>       AfterSep = 1;
>>     ELSE
>>     BEGIN
>>       IF (AfterSep = 0) THEN
>>         StrInt = StrInt || SUBSTRING(StrValue FROM 1 FOR 1);
>>       ELSE IF (DecCount >= Decimals) THEN
>>         BREAK;
>>       ELSE
>>       BEGIN
>>         StrFrac = StrFrac || SUBSTRING(StrValue FROM 1 FOR 1);
>>         DecCount = DecCount + 1;
>>       END
>>     END
>>     StrValue = SUBSTRING(StrValue FROM 2 FOR 50);
>>     SUSPEND;
>>   END
>>   Result = StrInt || '.' || StrFrac;
>>  END
>>  SUSPEND;
>> END^
>>
>> SELECT * FROM SP_Trunc(1.666, 2); /* Result: 1.66 */
>>
>>
>> Atenciosamente.
>>
>> Daniel P. Guimarães
>> Tecnobyte Informática
>> www.tecnobyte.com.br




Mais detalhes sobre a lista de discussão lista