在 C# 中用零初始化浮点列表
Initiate a float list with zeros in C#
我想用 zeros(0.0) 启动 N 个对象的列表。我想这样做:
var TempList = new List<float>(new float[(int)(N)]);
有没有更好(更有效)的方法?
您当前的解决方案创建一个数组,其唯一目的是用零初始化一个列表,然后丢弃该数组。这可能看起来效率不高。然而,正如我们将要看到的,它实际上是非常有效的!
这是一个不创建中间数组的方法:
int n = 100;
var list = new List<float>(n);
for (int i = 0; i < n; ++i)
list.Add(0f);
或者,您可以使用 Enumerable.Repeat()
提供 0f
"n" 次,如下所示:
var list = new List<float>(n);
list.AddRange(Enumerable.Repeat(0f, n));
但这两种方法都比较慢!
这是一个用于计时的小测试应用程序。
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
namespace Demo
{
public class Program
{
private static void Main()
{
var sw = new Stopwatch();
int n = 1024*1024*16;
int count = 10;
int dummy = 0;
for (int trial = 0; trial < 4; ++trial)
{
sw.Restart();
for (int i = 0; i < count; ++i)
dummy += method1(n).Count;
Console.WriteLine("Enumerable.Repeat() took " + sw.Elapsed);
sw.Restart();
for (int i = 0; i < count; ++i)
dummy += method2(n).Count;
Console.WriteLine("list.Add() took " + sw.Elapsed);
sw.Restart();
for (int i = 0; i < count; ++i)
dummy += method3(n).Count;
Console.WriteLine("(new float[n]) took " + sw.Elapsed);
Console.WriteLine("\n");
}
}
private static List<float> method1(int n)
{
var list = new List<float>(n);
list.AddRange(Enumerable.Repeat(0f, n));
return list;
}
private static List<float> method2(int n)
{
var list = new List<float>(n);
for (int i = 0; i < n; ++i)
list.Add(0f);
return list;
}
private static List<float> method3(int n)
{
return new List<float>(new float[n]);
}
}
}
这是我的 RELEASE 构建结果:
Enumerable.Repeat() took 00:00:02.9508207
list.Add() took 00:00:01.1986594
(new float[n]) took 00:00:00.5318123
事实证明,创建中间数组要快得多。但是,请注意此测试代码存在缺陷,因为它没有考虑分配中间数组(很难正确计时)引起的垃圾收集开销。
最后,有一种非常邪恶、令人讨厌的方法可以使用反射对其进行优化。但这很脆弱,将来可能无法正常工作,并且 永远,永远 不应该在生产代码中使用。
我在这里只是出于好奇:
private static List<float> method4(int n)
{
var list = new List<float>(n);
list.GetType().GetField("_size", BindingFlags.NonPublic | BindingFlags.Instance).SetValue(list, n);
return list;
}
与需要半秒的下一个最快方法相比,这样做可以将时间减少到不到十分之一秒。但是不要这样做。
有什么问题
float[] A = new float[N];
或
List<float> A = new List<float>(N);
请注意,尝试对编译器进行微观管理并不是优化。从做你想做的最干净的代码开始,让编译器做它的事。
编辑 1
List<float>
的解决方案生成一个空列表,仅在内部初始化 N
项。所以我们可以通过一些反射来欺骗它
static void Main(string[] args)
{
int N=100;
float[] array = new float[N];
List<float> list=new List<float>(N);
var size=typeof(List<float>).GetField("_size", BindingFlags.Instance|BindingFlags.NonPublic);
size.SetValue(list, N);
// Now list has 100 zero items
}
为什么不呢:
var itemsWithZeros = new float[length];
我想用 zeros(0.0) 启动 N 个对象的列表。我想这样做:
var TempList = new List<float>(new float[(int)(N)]);
有没有更好(更有效)的方法?
您当前的解决方案创建一个数组,其唯一目的是用零初始化一个列表,然后丢弃该数组。这可能看起来效率不高。然而,正如我们将要看到的,它实际上是非常有效的!
这是一个不创建中间数组的方法:
int n = 100;
var list = new List<float>(n);
for (int i = 0; i < n; ++i)
list.Add(0f);
或者,您可以使用 Enumerable.Repeat()
提供 0f
"n" 次,如下所示:
var list = new List<float>(n);
list.AddRange(Enumerable.Repeat(0f, n));
但这两种方法都比较慢!
这是一个用于计时的小测试应用程序。
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
namespace Demo
{
public class Program
{
private static void Main()
{
var sw = new Stopwatch();
int n = 1024*1024*16;
int count = 10;
int dummy = 0;
for (int trial = 0; trial < 4; ++trial)
{
sw.Restart();
for (int i = 0; i < count; ++i)
dummy += method1(n).Count;
Console.WriteLine("Enumerable.Repeat() took " + sw.Elapsed);
sw.Restart();
for (int i = 0; i < count; ++i)
dummy += method2(n).Count;
Console.WriteLine("list.Add() took " + sw.Elapsed);
sw.Restart();
for (int i = 0; i < count; ++i)
dummy += method3(n).Count;
Console.WriteLine("(new float[n]) took " + sw.Elapsed);
Console.WriteLine("\n");
}
}
private static List<float> method1(int n)
{
var list = new List<float>(n);
list.AddRange(Enumerable.Repeat(0f, n));
return list;
}
private static List<float> method2(int n)
{
var list = new List<float>(n);
for (int i = 0; i < n; ++i)
list.Add(0f);
return list;
}
private static List<float> method3(int n)
{
return new List<float>(new float[n]);
}
}
}
这是我的 RELEASE 构建结果:
Enumerable.Repeat() took 00:00:02.9508207
list.Add() took 00:00:01.1986594
(new float[n]) took 00:00:00.5318123
事实证明,创建中间数组要快得多。但是,请注意此测试代码存在缺陷,因为它没有考虑分配中间数组(很难正确计时)引起的垃圾收集开销。
最后,有一种非常邪恶、令人讨厌的方法可以使用反射对其进行优化。但这很脆弱,将来可能无法正常工作,并且 永远,永远 不应该在生产代码中使用。
我在这里只是出于好奇:
private static List<float> method4(int n)
{
var list = new List<float>(n);
list.GetType().GetField("_size", BindingFlags.NonPublic | BindingFlags.Instance).SetValue(list, n);
return list;
}
与需要半秒的下一个最快方法相比,这样做可以将时间减少到不到十分之一秒。但是不要这样做。
有什么问题
float[] A = new float[N];
或
List<float> A = new List<float>(N);
请注意,尝试对编译器进行微观管理并不是优化。从做你想做的最干净的代码开始,让编译器做它的事。
编辑 1
List<float>
的解决方案生成一个空列表,仅在内部初始化 N
项。所以我们可以通过一些反射来欺骗它
static void Main(string[] args)
{
int N=100;
float[] array = new float[N];
List<float> list=new List<float>(N);
var size=typeof(List<float>).GetField("_size", BindingFlags.Instance|BindingFlags.NonPublic);
size.SetValue(list, N);
// Now list has 100 zero items
}
为什么不呢:
var itemsWithZeros = new float[length];