【问题标题】:Does Casting Interpret the Value or just the Bits?铸造是解释价值还是仅仅解释位?
【发布时间】:2014-09-14 01:52:49
【问题描述】:

所以我一直理解强制转换意味着获取某事物的二进制文件,并将其解释为被强制转换的实体(必要时截断)。但是我注意到在 C# 中,您可以采用双精度,这是一种 64 位表示,包括指数和值。您可以将其转换为 long,它是不带指数的整数的 64 位表示。因此,在我看来,如果你将一个随机十进制值(比如 10.43245)存储在一个 double 中,并将其转换为 long,你会得到一些随机数,它恰好是二进制结果的 long .但是,这不是发生的情况,您只需得到截断的小数和 10 的值。

我对强制转换的定义是错误的吗?或者 c# 是否在这里稍微改变了一些规则,以便为程序员提供更多他们可能对这种演员的期望(我也假设 java 可能也这样做,那么 c++ 呢?)

【问题讨论】:

标签: c# casting double long-integer


【解决方案1】:

它没有什么神奇之处,但它必须做的不仅仅是位的直接转换。例如,看看您如何在汇编中将浮点数转换为整数:

[参考:http://www.codeproject.com/Articles/10679/Convert-Float-to-Int-using-Assembly-Language-Progr]

int ftoi(float flt)
{
    int i;
    _asm
    {
        mov  eax,flt; //loaded mem to acc
        rcl  eax,1;   //left shift acc to remove the sign
        mov  ebx,eax; //save the acc
        mov  edx,4278190080; //clear reg edx;
        and  eax,edx; //and acc to retrieve the exponent
        shr  eax,24;
        sub  eax,7fh; //subtract 7fh(127) to get the actual power 
        mov  edx,eax; //save acc val power
        mov  eax,ebx; //retrieve from ebx
        rcl  eax,8;     //trim the left 8 bits that contain the power
        mov  ebx,eax; //store
        mov  ecx, 1fh; //subtract 17 h
        sub  ecx,edx; 
        mov  edx,00000000h;
        cmp  ecx,0;
        je   loop2;
        shr  eax,1;
        or   eax,80000000h;        
loop1:    
        shr  eax,1; //shift (total bits - power bits);
        sub  ecx,1;
        add  edx,1;
        cmp  ecx,0;
        ja   loop1;
loop2:  
        mov  i, eax;        

//check sign +/-        
sign:
        mov  eax,flt;
        and  eax,80000000h;
        cmp  eax,80000000h;
        je     putsign;
    }

    return i;

putsign:
    return -i;
}

它正在移动,然后修剪,然后减去,然后再次移动。

【讨论】:

    【解决方案2】:

    在 c#cast is an explicit conversion. C# 规范 5.0 的第 6 节处理转换。特别是第 6.2.1 节介绍了如何在语言中定义数字显式转换。作为一项规则,他们会尽可能多地保留正在转换的数值。

    【讨论】:

      【解决方案3】:

      来自MSDN

      当您从 double 或 float 值转换为整数类型时,该值将被截断。如果生成的整数值超出目标值的范围,则结果取决于溢出检查上下文。在已检查的上下文中,会引发 OverflowException,而在未检查的上下文中,结果是目标类型的未指定值。

      因此,正如您所观察到的,当您将 double 转换为整数类型 long 时,您将获得截断值。

      【讨论】:

        【解决方案4】:

        转换的想法是将数据转换为另一种类型,通过所述转换几乎不会丢失数据。为了技术性,我们将引用Casting and Type Conversions 页面:

        隐式转换:不需要特殊语法,因为转换是类型安全的,不会丢失任何数据。示例包括从较小的整数类型到较大的整数类型的转换,以及从派生类到基类的转换。

        我们将重点关注“不会丢失任何数据”。

        我认为您在这里面临的问题是发生转换的位置,更重要的是,我们希望避免数据丢失的位置。

        按照您的示例,将double 10.43245 强制转换为long,我们面临这样一种情况,无论如何,都会存在类型隐式数据丢失:10.43245 不是 10,也不是是你的随机数字串吗? double 天生会在小数点后存储更多数字(特别是因为 long 存储一个实心零),因此无论如何转换此数字都会导致数据丢失。

        顺便说一句,这有点像将口语转换成摩尔斯电码。我们这样做,因为它有用。但是在这个过程中,我们仍然会失去一些有价值的语言品质。这是一种权衡,我们选择更重视数据传输的重要性,而不是以自然和情感的方式传达语音的重要性。

        因此,在承认我们正面临数据丢失这一事实之后,必须选择丢失数据最有意义的位置。我们可以以人类可读的形式丢失它,通过保留位顺序和所有这些,这就是你获得随机数字字符串的地方,或者我们可以以原始的二进制形式丢失它并尽可能多地保留 " of the number",在这种情况下,就是地板:十。

        本质上,这只是在建立第一批语言时所做的另一个简单权衡,没有人愿意改变一件好事。让(long)10.43245 解析为10 更有用。

        同样重要的是要记住,正如其他几个人指出的那样,这只是 默认 行为。因为存在这种转换,所以没有理由假设您不能将直接二进制值从一种类型转换为另一种类型。许多语言都有一些方法,比如 .NET 的BitConverter.DoubleToInt64Bits,它会进行这种一对一的位转换。作为一个典型的用例,它只是没有意义,而语言设计,特别是对于像我们主要处理的高级语言来说,就是让典型的用例尽可能高效和有效。

        【讨论】:

          【解决方案5】:

          强制转换会截断双精度数。您要查找的是 C# 中的 BitConverter.DoubleToInt64Bits 或 Java 中的 Double.doubleToLongBits

          【讨论】:

            【解决方案6】:
            long x = (long) doubleVal;
            

            是一个显式转换的例子,会尽量保留数值。

            如果您更喜欢操作双精度位,您可以使用不安全代码进行转换:

            long x;
            unsafe
            {
                x = *((long*) &val);
            }
            

            或者使用库函数BitConverter.DoubleToInt64Bits

            【讨论】:

              猜你喜欢
              • 1970-01-01
              • 2016-11-19
              • 1970-01-01
              • 2011-08-05
              • 2010-12-03
              • 1970-01-01
              • 1970-01-01
              • 2020-10-27
              • 2014-04-05
              相关资源
              最近更新 更多