Problema de ciclo e truncamento do servidor SQL

Encontrei um problema estranho no servidor SQL com arredondamentos.

Eis o meu exemplo:
declare @amount float = 178.69999999

select
    @amount as [amount],
    round(@amount, 6) as [round],
    round(round(@amount, 6), 2, 1) as [trim_1],
    floor(round(@amount, 6) * power(10.0, 2)) / power(10.0, 2) as [trim_2]
E aqui está o resultado que recebo:
+--------------+-------+--------+--------+
|    amount    | round | trim_1 | trim_2 |
+--------------+-------+--------+--------+
| 178.69999999 | 178.7 | 178.69 | 178.7  |
+--------------+-------+--------+--------+

a ideia geral aqui é que estou a tentar arredondar por 6 casas decimais, depois aparar / andar / truncado por 2 casas decimais. Isso significa que estou esperando um resultado de 178.7, mas estou obtendo um resultado de 178.69 para trim_1 (trim_2 é uma abordagem alternativa destinada a produzir o mesmo resultado).

Pelo que sei, sou usando adequadamente a função round, como a documentação do servidor SQL indica:

Sintaxe

ROUND ( numeric_expression , length [ ,function ] )  

função

é o tipo de operação a realizar. function deve ser tinyint, smallint, ou int. Quando a função é omitida ou tem um valor de 0 (por omissão), o numeric_ expressão é arredondado. Quando for especificado um valor diferente de 0, numeric_ expression está truncado.

Então eu esperaria {[6] } para igualar trim_2.

Aqui está o kicker: se eu passar o resultado de round como uma constante, e não como uma variável, ele funciona como esperado:

select round(178.7, 2, 1) -- Yields 178.7
O meu palpite é que o servidor SQL está a fazer algo estranho com pontos flutuantes, ou de alguma forma consegui perder alguma coisa. Para que conste, estou a usar o servidor SQL 2014, por isso talvez seja esse o meu problema.

Eu gostaria de obter o resultado de ... o mínimo possível de código, para que o meu resultado final pareça mais limpo.

Author: Boom, 2018-09-07

1 answers

Utilizar decimal em vez de float.

Retirado de flutuante e Real (Transact-SQL)

Os dados de vírgula flutuante são aproximados; portanto, nem todos os valores no intervalo do tipo de dados podem ser representados exactamente.

Substituir float por decimal no seu código tem o resultado desejado:

declare @amount decimal(18, 10) = 178.69999999

select
    @amount as [amount],
    round(@amount, 6) as [round],
    round(round(@amount, 6), 2, 1) as [trim_1],
    floor(round(@amount, 6) * power(10.0, 2)) / power(10.0, 2) as [trim_2]

Resultados:

╔════════════════╦════════════════╦════════════════╦════════════╗
║     amount     ║     round      ║     trim_1     ║   trim_2   ║
╠════════════════╬════════════════╬════════════════╬════════════╣
║ 178.6999999900 ║ 178.7000000000 ║ 178.7000000000 ║ 178.700000 ║
╚════════════════╩════════════════╩════════════════╩════════════╝
 2
Author: Simo, 2018-09-07 15:34:23