Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/csharp/284.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C#如何将整型项隐式转换为双精度项?_C# - Fatal编程技术网

C#如何将整型项隐式转换为双精度项?

C#如何将整型项隐式转换为双精度项?,c#,C#,是否有任何C#规范说明了整型术语(例如,int)到double术语的隐式转换应该如何工作?如果是这样的话,有人能告诉我算法或指导我去做吗 声明“float或double类型的实文本的值是通过在词汇结构->语法->词汇语法->词汇分析->标记->文本->实文本下使用IEEE的“四舍五入”模式确定的;然而,我无法找到任何关于隐式转换如何工作的信息 在同一规范中,我在Conversions->Implicit Conversions->Implicit numeric Conversions下找到的唯

是否有任何C#规范说明了整型术语(例如,
int
)到
double
术语的隐式转换应该如何工作?如果是这样的话,有人能告诉我算法或指导我去做吗

声明“float或double类型的实文本的值是通过在词汇结构->语法->词汇语法->词汇分析->标记->文本->实文本下使用IEEE的“四舍五入”模式确定的;然而,我无法找到任何关于隐式转换如何工作的信息

在同一规范中,我在Conversions->Implicit Conversions->Implicit numeric Conversions下找到的唯一内容是“从
int
uint
long
ulong
float
的转换以及从
long
ulong
double
的转换可能会导致精度损失,但绝不会导致幅度损失。”

我知道隐式转换并不像下面的程序所说明的那样遵循与实际文本相同的算法*:

编辑

上面的代码可能比它需要的更“复杂”。下面是另一个程序,希望能澄清我的问题

using System;
using System.Diagnostics;
namespace App
{
    internal static class Program
    {
        internal static void Main()
        {
            Debug.Assert(10648738977740919977 != 10648738977740919977d);
        }
    }
}
附录

正如General和mjwills在评论中所述,这几乎可以肯定是由于某些ISA(如x86)提供的扩展精度格式。至于.NET Core编译器为什么依赖扩展格式将
ulong
转换为
double
,但对真正的文本却不这样做,我无法确定这是否正确从技术上讲,这是一个“错误”,但如果两者都做相同的事情就好了。可以遵守上述规范,并且仍然使用扩展格式,因为IEEE 754-2019明确允许超过64位的精度。无论如何,
ulong
值可以完全适合x86扩展格式的64位有效位,因此不会导致舍入

TL;DR(又名编辑2)

在这篇编辑之前,我要说的是,我从根本上和哲学上反对我将要写的东西是必要的,甚至是可取的。我相信特定于一种特定编程语言的技术问题,如这种语言,仍然“适合”堆栈溢出,而不是任何其他堆栈交换站点(例如,计算机科学、理论计算机科学、数学和同伦类型理论等数学溢出)。这意味着想要知道事物的本质和细节,即使人们可能(错误地)认为这些事物会导致违反“最佳实践”-这仍然是一个有价值的问题。如果存在一个更基本的问题,那么可以就其单独提出一个问题

背景

我在VB.NET中编写的工作中创建了一个128位无符号整数类型,
U128
。我决定实现将
U128
术语显式转换为
Double
(即,用C语言来说,
Double
)术语。IEEE 754 binary64和binary32是非常普通的格式,因为它们几乎与base-10实数的格式相同。当然,它们必须被制成有限的位序列,并具有偏置指数。无论如何,我首先在Rust中实现了它,因为Rust有一个本机128位无符号整数类型,
u128
;而Rustonomicon明确说明了从
u128
术语到
f64
术语的强制转换的行为。这使我能够使用Rust测试我的算法;这并不奇怪,因为它是一个微不足道的算法≈ 12行代码我的实现匹配了Rust的一些边缘情况和10亿个随机生成的数字不,我没有花时间正式验证我的算法是正确的

然后我将我的算法移植到VB.NET——知道这里有多么流行C语言,我也用C语言重新编写了它,并确认它具有相同的行为,但我想确信在翻译过程中没有丢失任何东西。我能做的最好的事情就是比较
ULong
ULong
在C语言中的转换)术语到
Double
术语与等效的
ULong
s的类型转换为
U128
s到
Double
s。当我发现
10648738977740919977UL
与等效的
U128
的类型转换不同时,我确实感到沮丧(正确)假设取整FYI有问题,C#规范没有说明如何取整完全位于两个数字之间的数字;但正如预期的那样,它取整为偶数。当我比较第一个字节时——我使用的是我的cast与Rust的cast创建的Double的一点endian CPU,我发现我的是正确的在这一点上,我认为VB.NET(后来在C#中得到证实)有点“可疑”,因为我通常更信任Rust,正如前面所说的,该算法相当简单

幸运的是,我没有意识到C#允许程序在拥有扩展精度功能的CPU上使用扩展精度功能的(不幸的)怪癖,包括不兼容的CPU,如基于x86的CPU,其精度只有80位。如果我知道这一点,我可能会放弃它

直到我检查了
Double
术语的第一个字节,
10648738977740919977R
10648738977740919977d
),我真的很困惑,因为我发现它确实与我的算法一致。这怎么可能?我在同一个平台上使用了使用同一个编译器编译的同一台机器。最后,我正确地推测,词法分析器处理真实文本的方式可能与处理完整文本的方式有所不同转换为Doubles。为了测试这个理论,我把程序砍掉了
using System;
using System.Diagnostics;
namespace App
{
    internal static class Program
    {
        internal static void Main()
        {
            Debug.Assert(10648738977740919977 != 10648738977740919977d);
        }
    }
}
public static void Test()
{
    ulong lValue = 10648738977740919977;
    double dValue = 10648738977740919977;
    byte[] bytesFromLong = BitConverter.GetBytes(lValue);
    byte[] bytesFromDouble = BitConverter.GetBytes(dValue);
    byte[] bytesFromImplicitDouble = BitConverter.GetBytes((double)10648738977740919977);

    string HexAlphabet = "0123456789ABCDEF";
    string res = "Original Number : 10648738977740919977\nLong Bytes : 0x";
    foreach (byte b in bytesFromLong)
    {
        res += HexAlphabet[(int)(b >> 4)] + HexAlphabet[(int)(b & 0xF)];
    }
    res += "\nDouble Bytes : 0x";
    foreach (byte b in bytesFromDouble)
    {
        res += HexAlphabet[(int)(b >> 4)] + HexAlphabet[(int)(b & 0xF)];
    }
    res += "\nImplicit Double Bytes : 0x";
    foreach (byte b in bytesFromImplicitDouble)
    {
        res += HexAlphabet[(int)(b >> 4)] + HexAlphabet[(int)(b & 0xF)];
    }

    dValue = BitConverter.ToDouble(bytesFromDouble);
    res += "\nDouble read from Double bytes : " + String.Format("{0:0.#}", dValue);
    dValue = BitConverter.ToDouble(bytesFromImplicitDouble);
    res += "\nDouble read from Implicit Double bytes : " + String.Format("{0:0.#}",dValue);

    Console.WriteLine(res);
}