gpt4 book ai didi

c# SqlDecimal 在小数乘法中翻转符号

转载 作者:太空狗 更新时间:2023-10-29 20:19:36 24 4
gpt4 key购买 nike

我好像遇到了 more woes使用“我最喜欢的数据类型”SqlDecimal。我想知道这是否应该被视为错误。

当我在 SQL 中将两个小数字相乘时,我得到了预期的结果。当我通过 SQLCLR 函数运行相同的数字时,结果令人惊讶。

C#代码:

using System.Data.SqlTypes;
using Microsoft.SqlServer.Server;

namespace TestMultiplySQLDecimal
{
public static class Multiplier
{
[SqlFunction(DataAccess=DataAccessKind.None, IsDeterministic = true,IsPrecise = true)]
public static SqlDecimal Multiply(SqlDecimal a, SqlDecimal b)
{
if (a.IsNull || b.IsNull) return SqlDecimal.Null;
return a*b;
}
}
}

SQL 代码:

USE tempdb
GO
IF DB_ID('test') IS NOT NULL DROP DATABASE test
GO
CREATE DATABASE test
GO
USE test
GO

CREATE ASSEMBLY TestMultiplySQLDecimal
FROM 'C:\Users\tralalalaa\Documents\visual studio 2015\Projects\TestMultiplySQLDecimal\TestMultiplySQLDecimal\bin\Release\TestMultiplySQLDecimal.dll'
WITH PERMISSION_SET = SAFE
GO

CREATE FUNCTION dbo.fn_multiply(@a decimal(38,8), @b decimal(18,8))
RETURNS decimal(38,8)
EXTERNAL NAME TestMultiplySQLDecimal.[TestMultiplySQLDecimal.Multiplier].Multiply
GO
DECLARE @a decimal(38, 8),
@b decimal(18, 8),
@c decimal(38, 8),
@f decimal(38, 8)

SELECT @a = -0.00000450,
@b = 0.193,
@c = NULL,
@f = NULL

SELECT @c = @a * @b,
@f = dbo.fn_multiply(@a, @b)

SELECT multiply = null, c = @c, f = @f

结果是:c = -0.00000100f = +0.00000100

我知道“绝对”差异是“最小”的,而且我已经“淡化”了更大的错误,将其归咎于“舍入差异”......但是很难向客户解释负面乘以正面结果积极的。毕竟,T-SQL 很好地支持它......

我可以尝试使用 decimal(28,8) 而不是 decimal(38,8) 来解决它,但是我会遇到其他(完全不相关的)问题然后 =/


以下控制台应用程序表现出相同的问题,而无需涉及 SQL Server/SQLCLR:

using System;
using System.Data.SqlTypes;

namespace PlayAreaCSCon
{
class Program
{
static void Main(string[] args)
{
var dec1 = new SqlDecimal(-0.00000450d);
var dec2 = new SqlDecimal(0.193d);
dec1 = SqlDecimal.ConvertToPrecScale(dec1, 38, 8);
dec2 = SqlDecimal.ConvertToPrecScale(dec2, 18, 8);
Console.WriteLine(dec1 * dec2);
Console.ReadLine();
}
}
}

打印 0.000001

最佳答案

我相信该错误位于 1550 of SqlDecimal 行附近:

ret = new SqlDecimal(rgulRes, (byte)culRes, (byte)ResPrec, 
(byte)ActualScale, fResPositive);

if (ret.FZero ())
ret.SetPositive();

ret.AssertValid();

ret.AdjustScale(lScaleAdjust, true);

return ret;

它首先使用最终的比例参数构造一个新的小数。接下来,它根据传入的构造函数参数检查结果是否为“零”。

然后,在断言一切都有效后,它会执行比例调整。

在执行 FZero 检查时,结果类似于 -0.0000008685。我们知道 最终 比例将是 6,因为我们处于结果 scale and precision 的极限。 .好吧,前 6 位数字都是零。

只有在那之后,当调整比例时,它才会考虑舍入并将 1 移到最后的小数位。

这是一个错误。遗憾的是,decimal 的 SQL Server native 实现的源代码并未公开,因此我们无法将其与 SqlDecimal 的托管实现进行比较以了解它们的相似之处以及原始版本如何避免相同的错误。

关于c# SqlDecimal 在小数乘法中翻转符号,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/41938320/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com