Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/csharp/287.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#_Mono_Sse_Simd_Ieee 754 - Fatal编程技术网

C# 浮点范围缩减

C# 浮点范围缩减,c#,mono,sse,simd,ieee-754,C#,Mono,Sse,Simd,Ieee 754,我正在用Mono实现一些C#中的32位浮点三角运算,希望能利用Mono.Simd。我目前只缺少实距缩小。 我现在相当困惑,因为显然不包括浮点数和整数之间的转换,这意味着我无法使用通常的舍入/截断方法。但是,我可以在int和float之间按位转换 这样的事情可以做吗?如果需要,我可以上下缩放域,但理想情况下,范围缩减应导致域为[0,2 pi]或[-pi,pi]。我有一种预感,如果域是2的幂,那么可以用指数做一些IEEE魔术,但我真的不知道如何做 编辑: 好吧,我试着在这段C代码上乱搞,感觉好像我在

我正在用Mono实现一些C#中的32位浮点三角运算,希望能利用Mono.Simd。我目前只缺少实距缩小。 我现在相当困惑,因为显然不包括浮点数和整数之间的转换,这意味着我无法使用通常的舍入/截断方法。但是,我可以在int和float之间按位转换

这样的事情可以做吗?如果需要,我可以上下缩放域,但理想情况下,范围缩减应导致域为[0,2 pi]或[-pi,pi]。我有一种预感,如果域是2的幂,那么可以用指数做一些IEEE魔术,但我真的不知道如何做

编辑: 好吧,我试着在这段C代码上乱搞,感觉好像我在做什么(它不起作用,但小数部分总是正确的,至少以十进制/十进制10表示…)。核心原则似乎是获得域和输入指数之间的指数差,并用移动的尾数和调整后的指数组成一个新的浮点。。但它不适用于负数,我也不知道如何处理2的非幂(或任何分数-事实上,除2以外的任何东西都不起作用!)

我们可以看到,在所有情况下,输出都是一个新的数字,没有原始指数,尾数将一个量(即基于指数和尾数的第一个指数位被忽略后尾数的第一个非零位)移动到指数中。但我不确定这是否是正确的方法,它只是在纸上运行得很好

编辑3:
我被Mono版本2.0.50727.1433卡住了,请检查您的Mono版本,因为
ConvertToInt
ConvertToIntTruncated
应该在2.10版之后出现。

您可以将问题简化为采用浮点型1。为了简化这一点,可以使用位运算计算浮点的下限,然后使用浮点减法。以下是这些操作的(不安全)C#代码:

// domain is assumed to be positive
// returns value in [0,domain)
public float fmodulus(float val, float domain)
{
    if (val < 0)
    {
        float negative = fmodulus(-val, domain);
        if (domain - negative == domain)
            return 0;
        else
            return domain-negative;
    }

    if (val < domain)
        return val; // this avoids losing accuracy

    return fmodOne(val / domain) * domain;
}

// assumes val >= 1, so val is positive and the exponent is at least 0 
unsafe public float fmodOne(float val)
{
    int iVal = *(int*)&val;
    int uncenteredExponent = iVal >> 23;
    int exponent = uncenteredExponent - 127; // 127 corresponds to 2^0 times the mantissa
    if (exponent >= 23) 
        return 0; // not enough precision to distinguish val from an integer

    int unneededBits = 23 - exponent; // between 0 and 23
    int iFloorVal = (iVal >> unneededBits) << unneededBits; // equivalent to using a mask to zero the bottom bits of the mantissa
    float floorVal = *(float*)&iFloorVal; // convert the bit pattern back to a float

    return val-floorVal;
}
//假定域为正
//返回[0,域]中的值
公共浮点fmodulus(浮点值,浮点域)
{
if(val<0)
{
浮点负=fmodulus(-val,域);
if(域-负==域)
返回0;
其他的
返回域负;
}
if(val=1,则val为正,且指数至少为0
不安全的公共浮子fmodOne(浮子val)
{
int-iVal=*(int*)&val;
int uncenteredExponent=iVal>>23;
int-exponent=uncenteredExponent-127;//127对应尾数的2^0倍
如果(指数>=23)
返回0;//精度不够,无法区分val和整数
int unneedbits=23-指数;//介于0和23之间

int iFloorVal=(iVal>>不需要的位)啊,当然。问题是我正在Unity内部开发,出于某种疯狂的原因,Unity仍然坚持使用这个版本:bin>monop2——运行时版本mono.exe运行时版本:2.0.50727.1433这很不走运。在这种情况下,我想你最好的办法是通过转换每个组件来模拟这种转换,即
new Vector4f((int)v.X,(int)v、 Y,(内部)v.Z,(内部)v.W)
。我认为其他任何东西都会变慢。当然,这只适用于您的输入在
int
范围内的情况。或者,您可以使用本机库。我测试了该代码,实际上性能没有那么差-转换使执行时间增加了一倍,但仍然比我可以使用的最快标量代码快50%写入(仍然比Unity的Mathf库快200%)。下面是它生成的相关程序集:这使我的眼睛无法控制地流血。使用x64(从而拒绝访问FPU)看起来是这样的:这看起来很好。但是,64个版本中的simd代码要慢4倍左右…我不知道为什么。不过-OP中的问题仍然存在,因为我还需要它用于其他目的。例如,仅使用AVX无法将_m256d转换为整数(尽管AVX同时支持_m256d和_m256i,但您需要AVX2,因此纯浮点位的范围缩减仍然很有吸引力。我怀疑您是否可以通过手动旋转位来加快速度。即使对于AVX,您可能也应该回到SSE来转换为整数(如果可以的话;)也就是说,尾数移位和指数调整的方法应该适用于2的任意幂,因为你实际上只是在丢弃高阶位。我对你所说的域感到困惑。你说的域是[-pi,pi]但是你的域变量是一个int,而不是一个浮点数或双精度的区间。你想计算100模2pi吗?是的。我说的是不同的东西,因为我绝望地尝试各种方法(x模2pi=x-(int)(x/(2*pi))*2*pi),因此可以通过整数模拟域。因此,您希望能够仅使用位运算计算100 mod 2pi之类的值,而不能执行浮点除法或强制转换?我有重新解释/位强制转换、浮点和整数算术(/*+-)以及位运算(|&>),但没有本机转换(floor,int casts)。您可以在顶部的链接中看到可用操作的完整文档。这绝对是一个好主意。它对simd有相当多的控制逻辑,但还可以。不幸的是,我不能在Mono中使用它(因为Mono.simd不能在向量上移动单个数量),但你还是解决了这个问题,谢谢!我仍然对这个问题的其他观点感兴趣。
output = input % 2

[exponent] + [mantissa_bit_n_times_exponent]

3.5     = [2] + [1 + 0.5]                   ->[1] + [0.5]       = 1.5
4.5     = [4] + [0 + 0 + 0.5]               ->[0.5] + [0]       = 0.5
5.5     = [4] + [0 + 1 + 0.5]               ->[1] + [0.5]       = 1.5
2.5     = [2] + [0 + 0.5]                   ->[0.5] + [0]       = 0.5
2.25    = [2] + [0 + 0 + 0.25]              ->[0.25]            = 0.25
2.375   = [2] + [0 + 0 + 0.25 + 0.125]      ->[0.25] + [0.125]  = 0.375
13.5    = [8] + [4 + 0 + 1 + 0.5]           ->[1] + [0.5]       = 1.5
56.5    = [32] + [16 + 8 + 0 + 0 + 0 + 0.5] ->[0.5]             = 0.5
// domain is assumed to be positive
// returns value in [0,domain)
public float fmodulus(float val, float domain)
{
    if (val < 0)
    {
        float negative = fmodulus(-val, domain);
        if (domain - negative == domain)
            return 0;
        else
            return domain-negative;
    }

    if (val < domain)
        return val; // this avoids losing accuracy

    return fmodOne(val / domain) * domain;
}

// assumes val >= 1, so val is positive and the exponent is at least 0 
unsafe public float fmodOne(float val)
{
    int iVal = *(int*)&val;
    int uncenteredExponent = iVal >> 23;
    int exponent = uncenteredExponent - 127; // 127 corresponds to 2^0 times the mantissa
    if (exponent >= 23) 
        return 0; // not enough precision to distinguish val from an integer

    int unneededBits = 23 - exponent; // between 0 and 23
    int iFloorVal = (iVal >> unneededBits) << unneededBits; // equivalent to using a mask to zero the bottom bits of the mantissa
    float floorVal = *(float*)&iFloorVal; // convert the bit pattern back to a float

    return val-floorVal;
}