问题
I was trying to answer this SO question..
Given the following TSQL code
DECLARE @input1 INT = 100000
DECLARE @input2 INT = 40
DECLARE @input3 INT = 106833
DECLARE @X decimal(22,6) = 0
DECLARE @Y decimal(22,6) = 0.001
DECLARE @Z decimal(22,6)
DECLARE @r decimal(22,6)
DECLARE @v decimal(22,6)
SET @v = POWER(1/(1+ (@Y/12)), @input2)
SET @r = ((@Y/@input2) * @input1) / (1-@v)
IF (@r < @input3)
SET @Z = @Y + ABS((@X - @Y)/2)
ELSE
SET @Z = @Y - ABS((@X - @Y) /2)
SET @X = @Y
SET @Y = @Z
WHILE (ABS(@r - @input3) > 0.001)
BEGIN
SET @v = POWER(1/(1+ (@Y/12)), @input2)
SET @r = ((@Y/@input2) * @input1) / (1-@v)
IF (@r < @input3)
SET @Z = @Y + ABS((@X - @Y)/2)
ELSE
SET @Z = @Y - ABS((@X - @Y) /2)
SET @X = @Y
IF @Y = @Z
BREAK
SET @Y = @Z
END
SELECT (CAST(@Y AS decimal(22,6)) * 100)
I tried to convert it to C#
decimal input1 = 100000m;
decimal input2 = 40m;
decimal input3 = 106833m;
decimal x = 0m;
decimal y = 0.001m;
decimal z;
decimal r;
decimal v;
v = (decimal)(Math.Pow(Convert.ToDouble(1m / (1m + (y / 12m))), Convert.ToDouble(input2)));
r = ((y / input2) * input1) / (1 - v);
if (r<input3)
{
z = y + Math.Abs((x - y) / 2);
}
else
{
z = y - Math.Abs((x - y) / 2);
}
x = y;
y = z;
while (Math.Abs(r - input3) > 0.001m)
{
v = (decimal)(Math.Pow(Convert.ToDouble(1 / (1 + (y / 12))), Convert.ToDouble(input2)));
r = ((y / input2) * input1) / (1 - v);
if (r<input3)
{
z = y + Math.Abs((x - y) / 2);
}
else
{
z = y - Math.Abs((x - y) / 2);
}
x = y;
if (y==z) break;
y = z;
}
Console.WriteLine(y*100);
But the results are different.
The TSQL returns 4273.320000 whereas the C# code returns 0,1999999999999999999999998900. Furthermore if i put the exact same C# code inside a SqlFunction (CLR function) via
[Microsoft.SqlServer.Server.SqlFunction]
public static decimal CalcFinancialSpreading(decimal input1 = 100000, decimal input2 = 40, decimal input3 = 106833)
it returns 0
Does anybody spot the error?
回答1:
Your Solution it is. So answer is c# decimal precision is different than SQL, in SQL you are use 6 precision digit. So always set your number same like this (example) you can write your own helper converter class. :
public static decimal ConvertTo6(double d)
{
return Math.Round(Convert.ToDecimal(d), 6, MidpointRounding.AwayFromZero);
}
public static decimal ConvertTo6(decimal d)
{
return Math.Round(d, 6, MidpointRounding.AwayFromZero);
}
static void Main(string[] args)
{
int input1 = 100000;
int input2 = 40;
int input3 = 106833;
decimal x = 0.000000m;
decimal y = 0.001000m;
decimal z;
decimal r;
decimal v;
v = ConvertTo6(Pow(1 / (1 + (Convert.ToDouble(y) / 12d)), input2));
r = ConvertTo6(((y / input2) * input1) / (1 - v));
if (r < input3)
{
z = y + Math.Abs((x - y) / 2);
z = ConvertTo6(z);
}
else
{
z = y - Math.Abs((x - y) / 2);
z = ConvertTo6(z);
}
x = y;
y = z;
while (Math.Abs(r - input3) > 0.001m)
{
v = ConvertTo6((Math.Pow(Convert.ToDouble(1 / (1 + (y / 12))), Convert.ToDouble(input2))));
r = ((y / input2) * input1) / (1 - v);
r = ConvertTo6(r);
if (r < input3)
{
z = y + Math.Abs((x - y) / 2);
z = ConvertTo6(z);
}
else
{
z = y - Math.Abs((x - y) / 2);
z = ConvertTo6(z);
}
x = y;
if (y == z) break;
y = z;
}
Console.WriteLine(y * 100);
Console.Read();
}
来源:https://stackoverflow.com/questions/58729607/converting-tsql-code-to-c-sharp-data-type-problem