小编Asi*_*sik的帖子

在.NET中强制浮点是确定性的吗?

我一直在阅读很多关于.NET中浮点确定性的内容,即确保具有相同输入的相同代码将在不同的机器上提供相同的结果.由于.NET缺少Java的fpstrict和MSVC的fp:strict等选项,因此似乎一致认为使用纯托管代码无法绕过这个问题.C#游戏AI Wars已经决定使用定点数学,但这是一个麻烦的解决方案.

主要问题似乎是CLR允许中间结果存在于FPU寄存器中,这些寄存器具有比类型的原始精度更高的精度,从而导致不可预测的更高精度结果.CLR工程师David Notario撰写MSDN文章解释了以下内容:

请注意,对于当前规范,它仍然是提供"可预测性"的语言选择.在每次FP操作之后,该语言可以插入conv.r4或conv.r8指令以获得"可预测的"行为. 显然,这非常昂贵,不同的语言有不同的妥协.例如,C#什么都不做,如果你想缩小,你必须手动插入(浮点)和(双)强制转换.

这表明,只需为每个表达式和计算浮点数的子表达式插入显式强制转换,就可以实现浮点确定性.有人可能会在float周围编写一个包装器类型来自动执行此任务.这将是一个简单而理想的解决方案!

然而,其他评论表明它并非如此简单.Eric Lippert最近表示(强调我的):

在某些版本的运行时中,显式转换为float会产生与不这样做不同的结果.当你明确地转换为float时,C#编译器会给运行时提供一个提示,说"如果碰巧使用这个优化,就把这个东西从超高精度模式中取出".

这对运行时的"提示"是什么?C#规范是否规定显式转换为float会导致在IL中插入conv.r4?CLR规范是否规定conv.r4指令会使值缩小到其原始大小?只有当这两者都成立时,我们才能依靠显式转换来提供浮点"可预测性",正如David Notario所解释的那样.

最后,即使我们确实能够将所有中间结果强制转换为类型的原生大小,这是否足以保证跨机器的可重复性,还是有其他因素如FPU/SSE运行时设置?

.net c# floating-point ieee-754

47
推荐指数
2
解决办法
4835
查看次数

泛型与接口的实际优势

在这种情况下,使用泛型与接口有什么实际优势:

void MyMethod(IFoo f) 
{
}

void MyMethod<T>(T f) : where T : IFoo
{
}
Run Code Online (Sandbox Code Playgroud)

即你能做什么MyMethod<T>,你不能在非通用版本?我正在寻找一个实际的例子,我知道理论上的差异是什么.

我知道,在MyMethod<T>T 中,T将是具体的类型,但是我只能在方法体内将它用作IFoo.那么什么才是真正的优势呢?

c# generics polymorphism

42
推荐指数
4
解决办法
9864
查看次数

为什么const-correctness特定于C++?

免责声明:我知道有两个关于const-correctness有用的问题,但是,没有人讨论过如何在C++中使用const-correctness 而不是其他编程语言.此外,我对这些问题的答案不满意.

我现在使用了一些编程语言,在C++中让我烦恼的一件事就是const-correctness的概念.在Java,C#,Python,Ruby,Visual Basic等中没有这样的概念,这似乎对C++非常具体.

在你推荐我使用C++ FAQ Lite之前,我已经阅读了它,但这并不能说服我.完全有效,可靠的程序一直用Python编写,没有const关键字或等价物.在Java和C#中,对象可以声明为final(或const),但是没有const成员函数或const函数参数.如果函数不需要修改对象,则它可以采用仅提供对象的读访问权的接口.该技术同样可以在C++中使用.在我工作的两个真实的C++系统上,几乎没有使用const,一切都运行正常.因此,对于让const污染代码库的有用性,我还远没有卖掉.

我想知道在C++中它是什么让const成为必要,而不是其他编程语言.

到目前为止,我只看到了必须使用const的一种情况:

#include <iostream>

struct Vector2 {
    int X;
    int Y;
};

void display(/* const */ Vector2& vect) {
    std::cout << vect.X << " " << vect.Y << std::endl;
}

int main() {
    display(Vector2());
}
Run Code Online (Sandbox Code Playgroud)

Visual Studio接受使用const注释掉的编译,但是使用警告C4239时,使用非标准扩展.所以,如果你想要传递临时代码,避免副本和保持标准兼容的语法简洁,你必须通过const引用,不管它.不过,这更像是一个怪癖,而不是一个根本原因.

否则,实际上不存在必须使用const的情况,除非与使用const的其他代码连接.在我看来,康斯特似乎不是一个自以为是的瘟疫,它蔓延到它接触到的一切:

const在C++中工作的原因是因为你可以把它丢弃.如果你不能把它扔掉,那么你的世界就会糟透了.如果声明一个采用const Bla的方法,则可以将它传递给非const Bla.但如果是相反的方式你不能.如果声明一个采用非const Bla的方法,则不能将它传递给const Bla.所以现在你被卡住了.所以你逐渐需要一个不是const的所有东西的const版本,你最终得到了一个阴影世界.在C++中,你可以使用它,因为与C++中的任何东西一样,无论你是否想要这个检查,它都是纯粹可选的.如果你不喜欢它,你可以打破常量.

Anders Hejlsberg(C#架构师),CLR设计选择

c++ const const-correctness

40
推荐指数
7
解决办法
7237
查看次数

如何控制C数学是否使用SSE2?

我在fp:strict模式下使用MSVC进入了C库的超越数学函数的汇编.他们似乎都遵循相同的模式,这就是发生的事情sin.

首先,从名为"disp_pentium4.inc"的文件中有一个调度例程.它检查变量___use_sse2_mathfcns是否已设置; 如果是这样,电话__sin_pentium4,否则打电话__sin_default.

__sin_pentium4 (在"sin_pentium4.asm"中)首先将参数从x87 fpu传送到xmm0寄存器,使用SSE2指令执行计算,然后将结果加载回fpu.

__sin_default(在"sin.asm"中)将变量保存在x87堆栈上并简单地调用fsin.

因此,在这两种情况下,操作数推x87堆栈上和它返回为好,使之透明的来电,但如果___use_sse2_mathfcns被定义,在SSE2而不是的x87实际执行的操作.

这种行为是对我来说很有趣,因为的x87超越函数是臭名昭著的具有取决于实施的行为稍有不同,而SSE2的给定代码块要经常给重现的结果.

有没有办法确定在编译或运行时是否会使用SSE2代码路径?我不是很精通编写程序集,所以如果这涉及编写任何程序集,那么代码示例将不胜感激.

c++ floating-point sse deterministic visual-c++

21
推荐指数
1
解决办法
1784
查看次数

如何使用Atom编辑器创建,构建,运行和调试Rust程序?

我正在寻找在Atom编辑器中创建,构建,运行和调试第一个Rust应用程序的分步说明.

到目前为止,我已经安装了Atom编辑器,安装了软件包language-rust,并且毫无结果地试图在编辑器中找到一个选项来创建Rust"项目"或"包",而我的google-fu失败了.

免责声明:我在Windows上,非常熟悉Visual Studio,不熟悉类似*nix的开发环境,但渴望尝试Rust.

windows rust atom-editor

18
推荐指数
1
解决办法
6032
查看次数

C#方法组类型推断

我正在尝试编写一个提供参数并调用函数的泛型方法,如下所示:

class MyClass {
    public int Method(float arg) => 0;
}

TResult Call<T1, TResult>(Func<T1, TResult> func) =>
    func(default(T1));

void Main()
{
    var m = new MyClass();
    var r1 = Call<float, int>(m.Method);
    var r2 = Call(m.Method); // CS0411
}
Run Code Online (Sandbox Code Playgroud)

最后一行无法使用CS0411进行编译.是否有任何解决方法可以在这里使用类型推断?

使用案例:使用AutoFixture生成函数调用参数.

c# generics type-inference

14
推荐指数
1
解决办法
510
查看次数

与浮点数不一致的乘法性能

在.NET中测试浮点数的性能时,我偶然发现了一个奇怪的情况:对于某些值,乘法似乎比正常慢.以下是测试用例:

using System;
using System.Diagnostics;

namespace NumericPerfTestCSharp {
    class Program {
        static void Main() {
            Benchmark(() => float32Multiply(0.1f), "\nfloat32Multiply(0.1f)");
            Benchmark(() => float32Multiply(0.9f), "\nfloat32Multiply(0.9f)");
            Benchmark(() => float32Multiply(0.99f), "\nfloat32Multiply(0.99f)");
            Benchmark(() => float32Multiply(0.999f), "\nfloat32Multiply(0.999f)");
            Benchmark(() => float32Multiply(1f), "\nfloat32Multiply(1f)");
        }

        static void float32Multiply(float param) {
            float n = 1000f;
            for (int i = 0; i < 1000000; ++i) {
                n = n * param;
            }
            // Write result to prevent the compiler from optimizing the entire method away
            Console.Write(n);
        }

        static void Benchmark(Action func, …
Run Code Online (Sandbox Code Playgroud)

.net c# floating-point performance

13
推荐指数
1
解决办法
611
查看次数

大对象堆浪费

我注意到我的应用程序内存耗尽比它应该更快.它创建了许多每个几兆字节的字节数组.但是,当我查看vmmap的内存使用情况时,似乎.NET为每个缓冲区分配的内容远远超过了需要.确切地说,当分配9兆字节的缓冲区时,.NET会创建一个16兆字节的堆.剩余的7兆字节不能用于创建另一个9兆字节的缓冲区,因此.NET会创建另外的16兆字节.所以每个9MB缓冲区浪费7MB的地址空间!

这是一个示例程序,它在32位.NET 4中分配106个缓冲区后抛出OutOfMemoryException:

using System.Collections.Generic;

namespace CSharpMemoryAllocationTest
{
    class Program
    {
        static void Main(string[] args)
        {
            var buffers = new List<byte[]>();
            for (int i = 0; i < 130; ++i)
            {
                buffers.Add(new byte[9 * 1000 * 1024]);
            }

        }
    }
}
Run Code Online (Sandbox Code Playgroud)

请注意,您可以将阵列的大小增加到16*1000*1024,并在内存不足之前仍然分配相同数量的缓冲区.

VMMap显示了这个:

在此输入图像描述

另请注意,托管堆的总大小与总通信大小之间几乎有100%的差异.(1737MB vs 946MB).

有没有一种可靠的方法解决.NET上的这个问题,即我可以强制运行时分配不超过我实际需要的,或者可能用于几个连续缓冲区的更大的托管堆?

.net c#

13
推荐指数
2
解决办法
1190
查看次数

额外的蜥蜴和尾巴的目的是什么.在F#实现与C#?

以下C#函数:

T ResultOfFunc<T>(Func<T> f)
{
    return f();
}
Run Code Online (Sandbox Code Playgroud)

毫不奇怪地汇编到这个:

IL_0000:  ldarg.1     
IL_0001:  callvirt    05 00 00 0A 
IL_0006:  ret  
Run Code Online (Sandbox Code Playgroud)

但是等效的F#功能:

let resultOfFunc func = func()
Run Code Online (Sandbox Code Playgroud)

汇编到这个:

IL_0000:  nop         
IL_0001:  ldarg.0     
IL_0002:  ldnull      
IL_0003:  tail.       
IL_0005:  callvirt    04 00 00 0A 
IL_000A:  ret 
Run Code Online (Sandbox Code Playgroud)

(两者都处于发布模式).开头有一个额外的小窍门,我并不太好奇,但有趣的是附加ldnulltail.说明.

我的猜测(可能是错误的)是ldnull必要的,如果函数是void这样,它仍然返回something(unit),但这并不能解释tail.指令的目的是什么.如果函数确实在栈上推送了某些东西会发生什么呢?是不是它会被一个不会弹出的额外null所困?

c# f# cil tail-recursion tail-call-optimization

12
推荐指数
1
解决办法
211
查看次数

是否可以实现递归"SelectMany"?

众所周知,Enumerable.SelectMany将序列序列展平为单个序列.如果我们想要一种能够使序列序列序列变平,等等递归的方法怎么办?

我很快就提出了一个实现使用ICollection<T>,即急切评估,但我仍然在摸索如何使用yield关键字进行懒惰评估.

static List<T> Flatten<T>(IEnumerable list)  {
    var rv = new List<T>();
    InnerFlatten(list, rv);
    return rv;
}

static void InnerFlatten<T>(IEnumerable list, ICollection<T> acc) {
    foreach (var elem in list) {
        var collection = elem as IEnumerable;
        if (collection != null) {
            InnerFlatten(collection, acc);
        }
        else {
            acc.Add((T)elem);
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

有任何想法吗?任何.NET语言欢迎中的示例.

.net c# recursion f#

11
推荐指数
2
解决办法
3013
查看次数