问题是
是否还有其他(和/或更快)的基本2log实现?
应用
log2(int)和log2(float)操作在许多不同的上下文中非常有用.仅举几例:压缩算法,3d引擎和机器学习.在几乎所有这些上下文中,它们都被用在被称为数十亿次的低级代码中......尤其是log2(int)操作非常有用.
因为我发现自己一直在使用log2,所以我不想给出我正在处理的特定应用程序.同样的事实是,这是一个真正的性能排水器(如各种应用程序的性能测试所示).对我来说,尽可能快地获得这个是关键.
底部添加了测试所有实现的完整源代码,因此您可以自己查看.
当然......至少运行3次测试并确保计数器大到足以达到几秒钟.我也做'添加'操作,以确保整个循环不被JIT'ter神奇地删除.让我们开始真正的工作吧.
琐碎的实施
C#中2log的简单实现是:
(int)(Math.Log(x) / Math.Log(2))
Run Code Online (Sandbox Code Playgroud)
这个实现很简单,但也很慢.它需要2个Log操作,这本身就很慢.当然,我们可以通过设定1.0/Math.Log(2)常数来优化它.
请注意,我们需要稍微修改此常量以获得正确的结果(作为浮点错误的结果)或添加一个小数字以获得正确的结果.我选择了后者,但这并不重要 - 最终结果在所有情况下都很慢.
表查找
更快的解决方案是使用查找表.虽然您可以使用任何2的幂的查找表,但我通常使用256或64K条目的表大小.
首先我们创建查找表:
lookup = new int[256];
for (int i = 1; i < 256; ++i)
{
lookup[i] = (int)(Math.Log(i) / Math.Log(2));
}
Run Code Online (Sandbox Code Playgroud)
接下来,我们实现2log如下:
private static int LogLookup(int i)
{
if (i >= 0x1000000) { return lookup[i >> 24] + 24; }
else if (i >= 0x10000) { return lookup[i >> 16] + 16; }
else if (i >= 0x100) { return …Run Code Online (Sandbox Code Playgroud) 我总是理解结构(值类型)包含结构字段中定义的字节数...但是,我做了一些测试,并且空结构似乎有一个例外:
public class EmptyStructTest
{
static void Main(string[] args)
{
FindMemoryLoad<FooStruct>((id) => new FooStruct());
FindMemoryLoad<Bar<FooStruct>>((id) => new Bar<FooStruct>(id));
FindMemoryLoad<Bar<int>>((id) => new Bar<int>(id));
FindMemoryLoad<int>((id) => id);
Console.ReadLine();
}
private static void FindMemoryLoad<T>(Func<int, T> creator) where T : new()
{
GC.Collect(GC.MaxGeneration);
GC.WaitForFullGCComplete();
Thread.MemoryBarrier();
long start = GC.GetTotalMemory(true);
T[] ids = new T[10000];
for (int i = 0; i < ids.Length; ++i)
{
ids[i] = creator(i);
}
long end = GC.GetTotalMemory(true);
GC.Collect(GC.MaxGeneration);
GC.WaitForFullGCComplete();
Thread.MemoryBarrier();
Console.WriteLine("{0} {1}", ((double)end-start) / 10000.0, ids.Length);
}
public struct …Run Code Online (Sandbox Code Playgroud) 在做一些奇特的代码生成时,我遇到了一个我不理解的堆栈溢出.
我的代码基本上是这样的:
static Tuple<string, int>[] DoWork()
{
// [ call some methods ]
Tuple<string, int>[] tmp = new Tuple<string, int>[100];
tmp[0] = new Tuple<string, int>("blah 1", 0);
tmp[1] = new Tuple<string, int>("blah 2", 1);
tmp[2] = new Tuple<string, int>("blah 3", 2);
// ...
tmp[99] = new Tuple<string, int>("blah 99", 99);
return tmp;
}
Run Code Online (Sandbox Code Playgroud)
如果你使用这里的小数字(100)一切正常.如果数字很大,就会发生奇怪的事情.在我的情况下,我尝试发出大约10K行代码,这会触发堆栈溢出异常.
那么......为什么我认为这很奇怪:
再现陌生感......
我无法在最小的测试用例中重现stackoverflow,但我确实注意到它似乎是在64位.NET 4.5上触发的.我能给出的是一些证明正在发生的事情的证据.
另请注意,真正的代码使用Reflection.Emit代码生成此代码...它不像代码本身具有所有这些代码行...发出的IL代码是正确的BTW.
在Visual Studio中 - 在最后一行放置一个断点.注意在反汇编中使用堆栈指针(ASM,而不是IL).
现在在代码中添加一个新行 - 例如tmp[100] = // the usuals.在这里放一个断点,注意使用的堆栈空间增长.
至于尝试使用最小的测试用例来重现Reflection.Emit …
最近我使用了相当多的代码生成,通常与部分类相结合.基本上设置如下:
问题是当我使用像"生成方法"这样的Intellisense功能时,它们由于某种原因在包含生成代码的文件中生成.显然我不希望这样.
我的问题是:是否有可能生成一些提示告诉Intellisense它不应该触摸某些'cs'文件(而是其他部分类)?
更新
回想起来,我应该注意到我正在使用自定义工具来生成代码.它不是EF或简单的转换; 代码生成中涉及到相当多的逻辑.此外,它还使用部分类生成完整的命名空间和类结构.通过从csproj文件中提取"root命名空间" 然后使用文件夹结构来确定绝对命名空间(它与Linq2sql的工作方式类似).
xanatos(谢谢!)建议的答案有效:intellisense对名称进行操作排序,然后按字母顺序对名称进行排序,然后选择列表中的第一项.这意味着您可以生成一个zzzz.foo.cs(虽然有点难看)将正常工作.我刚刚进行了一些实验,发现该功能find all references返回了VS似乎使用的顺序.事实证明,它的工作原理如下:
假设您有一个自定义工具,可以处理文件名foo.bar并将其转换为foo.cs.自定义工具将生成内容作为字符串并将其传递回Visual studio(这就是自定义工具的工作方式......).结果将在一个名为的文件中foo.cs.
现在,我很惊讶地发现Intellisense不会将其排序为foo.cs而是将其排序为foo.bar\foo.cs.换句话说:无论你如何命名您的自定义工具"CS"的输出,你必须到基本文件重命名foo.bar为类似zoo.bar.
虽然这可能是一种解决方法,但我很愿意接受它作为答案,因为我必须给我的项目中的文件奇怪的名字(名字有意义......).此外,我的一些自定义工具依赖于他们的文件名,因此也会被破坏...
因此,我仍然愿意就如何正确解决这个问题提出建议.
在.NET中众所周知,类型不是垃圾收集,这意味着如果你正在玩f.ex. Reflection.Emit,你必须要小心卸载AppDomains等等......至少我是如何理解事情是如何运作的.
这让我想知道泛型类型是否是垃圾收集的,更准确一点:用MakeGenericType例如基于用户输入创建的泛型.:-)
所以我构建了以下测试用例:
public interface IRecursiveClass
{
int Calculate();
}
public class RecursiveClass1<T> : IRecursiveClass
where T : IRecursiveClass,new()
{
public int Calculate()
{
return new T().Calculate() + 1;
}
}
public class RecursiveClass2<T> : IRecursiveClass
where T : IRecursiveClass,new()
{
public int Calculate()
{
return new T().Calculate() + 2;
}
}
public class TailClass : IRecursiveClass
{
public int Calculate()
{
return 0;
}
}
class RecursiveGenericsTest
{
public static int CalculateFromUserInput(string str)
{ …Run Code Online (Sandbox Code Playgroud) Func<...>在使用继承和泛型时,我一直无法理解在整个代码中使用的性能特征- 这是我发现自己一直使用的组合.
让我从一个最小的测试用例开始,这样我们都知道我们在谈论什么,然后我会发布结果,然后我将解释我期望的内容以及为什么......
最小的测试用例
public class GenericsTest2 : GenericsTest<int>
{
static void Main(string[] args)
{
GenericsTest2 at = new GenericsTest2();
at.test(at.func);
at.test(at.Check);
at.test(at.func2);
at.test(at.Check2);
at.test((a) => a.Equals(default(int)));
Console.ReadLine();
}
public GenericsTest2()
{
func = func2 = (a) => Check(a);
}
protected Func<int, bool> func2;
public bool Check2(int value)
{
return value.Equals(default(int));
}
public void test(Func<int, bool> func)
{
using (Stopwatch sw = new Stopwatch((ts) => { Console.WriteLine("Took {0:0.00}s", ts.TotalSeconds); }))
{
for (int i = 0; i < 100000000; …Run Code Online (Sandbox Code Playgroud) 我正在尝试将LLVM IR中的方法调用回C++代码.我正在使用64位Visual C++,或者正如LLVM所描述的那样:
Machine CPU: skylake
Machine info: x86_64-pc-windows-msvc
Run Code Online (Sandbox Code Playgroud)
对于整数类型和指针类型,我的代码工作正常.但是,浮点数似乎有点奇怪.
基本上这个电话看起来像这样:
struct SomeStruct
{
static void Breakpoint( return; } // used to set a breakpoint
static void Set(uint8_t* ptr, double foo) { return foo * 2; }
};
Run Code Online (Sandbox Code Playgroud)
和LLVM IR看起来像这样:
define i32 @main(i32, i8**) {
varinit:
// omitted here: initialize %ptr from i8**.
%5 = load i8*, i8** %instance0
// call to some method. This works - I use it to set a breakpoint
call void @"Helper::Breakpoint"(i8* %5)
// this …Run Code Online (Sandbox Code Playgroud) 为了创建应该在ASP.NET中使用的自定义数据源,我创建了一个自定义数据源类,一个自定义编辑器和一个自定义可序列化类.
我无法理解的是为什么它不起作用......即使我可能有更多的属性而不是必需的(我一直在浏览和尝试几个小时),从我的理解PersistenceMode(PersistenceMode.InnerProperty)应该做的诀窍......此外,在我看来,我的代码类似于为什么我不能在WebForm中声明UserControl的子元素(属性)?.
代码的工作原理如下:
[ParseChildren(true)]
[PersistChildren(true)]
public class MyDataSource : DataSourceControl
{
// [much more irrelevant code...]
[Browsable(true)]
[EditorBrowsable(EditorBrowsableState.Always)]
[PersistenceMode(PersistenceMode.InnerProperty)]
[MergableProperty(false)]
[TypeConverter(typeof(ExpandableObjectConverter))]
[DesignerSerializationVisibility(DesignerSerializationVisibility.Content)]
[Editor(typeof(Editors.ResultRequestEditor), typeof(System.Drawing.Design.UITypeEditor))]
public ResultRequest Request { get; set; }
}
[Serializable]
[PersistChildren(true)]
[TypeConverter(typeof(ExpandableObjectConverter))]
[ParseChildren(true)]
public class ResultRequest
{
[Browsable(true)]
[EditorBrowsable(EditorBrowsableState.Always)]
public string ColumnName { get; set; }
[Browsable(true)]
[EditorBrowsable(EditorBrowsableState.Always)]
public Type ColumnType { get; set; }
[Browsable(false)]
[EditorBrowsable(EditorBrowsableState.Always)]
public object[] ResultTypeParameters { get; set; }
}
Run Code Online (Sandbox Code Playgroud)
自定义编辑器似乎工作:使用它后,VS中的属性正确更新.
但是,在更新某些内容后,信息不会保留在ASPX文件中:
<cc1:MyDataSource ID="SearchDataSource1" runat="server" ProviderID="MyProvider1" />
Run Code Online (Sandbox Code Playgroud)
我期望的是数据源中的一些序列化,例如: …
众所周知,.NET垃圾收集器不只是"删除"堆上的对象,而且还使用内存压缩来对抗内存碎片.根据我的理解,基本上将内存复制到一个新的地方,旧的地方在某些时候被删除.
我的问题是:这是如何工作的?
我最感兴趣的是GC在一个单独的线程中运行,这意味着我们正在处理的对象可以在我们执行代码时由GC移动.
问题的技术细节
为了说明,让我更详细地解释一下我的问题:
class Program
{
private int foo;
public static void Main(string[] args)
{
var tmp = new Program(); // make an object
if (args.Length == 2) // depend the outcome on a runtime check
{
tmp.foo = 12; // set value ***
}
Console.WriteLine(tmp.foo);
}
}
Run Code Online (Sandbox Code Playgroud)
在这个小例子中,我们创建一个对象并在对象上设置一个简单变量.点'***'对问题来说很重要:如果'tmp'的地址移动,'foo'会引用不正确的东西,一切都会破坏.
垃圾收集器在单独的线程中运行.所以据我所知,'tmp'可以在这个指令中移动,'foo'最终会得到不正确的值.但不知何故,魔法发生了,但事实并非如此.
至于反汇编程序,我注意到编译后的程序确实采用了'foo'的地址并移动了值'12:
000000ae 48 8B 85 10 01 00 00 mov rax,qword ptr [rbp+00000110h]
000000b5 C7 40 08 0C 00 00 00 mov dword ptr [rax+8],0Ch
Run Code Online (Sandbox Code Playgroud)
我或多或少期望在这里看到一个间接指针,可以更新 …
最近,我一直试图让SEH异常处理与MCJIT一起在LLVM(3.8.1)中工作.到目前为止没有运气.
根据我从网站(http://llvm.org/docs/ExceptionHandling.html)的理解,这几乎是如何实现的.使用clang编译一小段代码可以得到几乎相同的LLVM IR代码.然而,当我尝试它时,程序崩溃了一个令人讨厌的Stack cookie instrumentation code detected a stack-based buffer overrun..
为了说明我一直在尝试做的事情,我创建了一个最小的测试用例(我为代码量道歉...):
#include <string>
#include <iostream>
#include <exception>
#pragma warning(push)
#pragma warning(disable: 4267)
#pragma warning(disable: 4244)
#pragma warning(disable: 4800)
#pragma warning(disable: 4996)
#pragma warning(disable: 4141)
#pragma warning(disable: 4146)
#pragma warning(disable: 4624)
#pragma warning(disable: 4291)
#define DONT_GET_PLUGIN_LOADER_OPTION
#include "llvm/ADT/StringRef.h"
#include "llvm/ADT/StringMap.h"
#include "llvm/ADT/Triple.h"
#include "llvm/PassRegistry.h"
#include "llvm/IR/DataLayout.h"
#include "llvm/IR/LegacyPassManager.h"
#include "llvm/LinkAllPasses.h"
#include "llvm/Analysis/Passes.h"
#include "llvm/Analysis/TargetTransformInfo.h"
#include "llvm/ExecutionEngine/ExecutionEngine.h"
#include "llvm/ExecutionEngine/GenericValue.h"
#include "llvm/ExecutionEngine/Interpreter.h"
#include "llvm/ExecutionEngine/MCJIT.h"
#include "llvm/IR/Constants.h"
#include "llvm/IR/Type.h" …Run Code Online (Sandbox Code Playgroud) c# ×8
.net ×6
generics ×3
llvm ×2
llvm-ir ×2
performance ×2
asp.net ×1
c++11 ×1
controls ×1
datasource ×1
editor ×1
inheritance ×1
intellisense ×1
math ×1
runtime ×1
seh ×1
types ×1
value-type ×1