为了测试一下js和Canvas的计算能力,做了一个Mandelbrot的分形图,支持鼠标Zoom In。Mandelbrot的定义很简单,虚数平面的每个点(x,y),通过反复计算zn+1 = zn2 + c,z0 = 0。只有结果收敛才属于Mandelbrot,否则根据n的设定一个颜色,越大越深,代表接近属于集合的点,可以把集合中的点理解为n=无穷大。推荐在chrome中打开本页,还支持firefox和ie9。 拖动鼠标可以明显发现chrome是最流畅的。
更为专业的Mandelbrot请check这里 http://www.atopon.org/mandel/
<canvas id="canvas" width="600" height="480" style="margin-left:100px">
<p>Your browser does not support the canvas element.</p>
</canvas>
<p><input id="reset" type="button" value="Reset" /></p>
<script>
var canvas = document.getElementById('canvas');
var context = canvas.getContext('2d');
var width = canvas.width ,height = canvas.height;
var maxIterations = 100;
var minRe = -2.0;
var maxRe = 1.0;
var minIm = -1;
var maxIm = minIm+(maxRe-minRe)*height/width;
reset();
document.getElementById("reset").onclick = reset;
canvas.onmousedown = function (evt) {
var x0 = evt.pageX - canvas.offsetLeft;
var y0 = evt.pageY - canvas.offsetTop;
var x1, y1, w, h;
var imgd = context.getImageData(0, 0, width, height);
update(evt);
function update(evt) {
x1 = evt.pageX - canvas.offsetLeft;
y1 = evt.pageY - canvas.offsetTop;
w = Math.abs(x1 - x0), h = Math.abs(y1 - y0);
}
function clear(evt) {
if (w && h) {
context.clearRect(0, 0, width, height);
context.putImageData(imgd, 0, 0);
}
}
canvas.onmousemove = function (evt) {
clear(evt);
update(evt);
context.strokeStyle = "red";
context.strokeRect(x0 < x1 ? x0 : x1, y0 < y1 ? y0 : y1, w, h);
}
canvas.onmouseup = function (evt) {
clear(evt);
canvas.onmousemove = canvas.onmouseup = null;
minRe = minRe + (maxRe - minRe) / width * (x0 < x1 ? x0 : x1);
maxRe = minRe + (maxRe - minRe) / width * w;
minIm = minIm + (maxIm - minIm) / height * (y0 < y1 ? y0 : y1);
maxIm = minIm + (maxIm - minIm) / height * h;
draw();
}
}
function reset() {
minRe = -2.0;
maxRe = 1.0;
minIm = -1;
maxIm = minIm + (maxRe - minRe) * height / width;
draw();
}
function draw() {
context.fillRect(0, 0, width, height);
var imgd = context.getImageData(0, 0, width, height)
var pix = imgd.data;
var drawPixel = function (x, y, itr) {
var i = (y * width + x) * 4;
pix[i] = pix[i + 1] = pix[i + 2] = Math.round(itr * 255 / maxIterations);
}
mandelbrot(width, height, drawPixel);
context.putImageData(imgd, 0, 0);
}
function mandelbrot(imageWidth, imageHeight, drawPixel) {
var re_factor = (maxRe-minRe)/(imageWidth-1);
var im_factor = (maxIm-minIm)/(imageHeight-1);
for(var y=0; y<imageHeight; ++y)
{
var c_im = maxIm - y*im_factor;
for(var x=0; x<imageWidth; ++x)
{
var c_re = minRe + x*re_factor;
var z_re = c_re, z_im = c_im;
var isInside = true;
var n = 0;
for(; n<maxIterations; ++n)
{
var z_re2 = z_re*z_re, z_im2 = z_im*z_im;
if(z_re2 + z_im2 > 4)
{
isInside = false;
break;
}
z_im = 2*z_re*z_im + c_im;
z_re = z_re2 - z_im2 + c_re;
}
if (!isInside) { drawPixel(x, y, n); }
}
}
}
</script>
class Student
{
public string Name { get; set; }
}
static double Test(int loop, Student stu, Func<Student, string> action)
{
var watch = Stopwatch.StartNew();
string s = null;
for (var i = 0; i < loop; i++)
s = action(stu);
return watch.ElapsedTicks;
}
static Func<Student, string> NativeGetter()
{
return s => s.Name;
}
static Func<Student, string> ReflectedGetter()
{
var type = typeof (Student);
var prop = type.GetProperty("Name");
return s => (string)prop.GetValue(s, null);
}
static Func<Student, string> EmittedGetter()
{
var dm = new DynamicMethod(name: "EmittedGetter", returnType: typeof(string), parameterTypes: new[] { typeof(Student) }, owner: typeof(Student));
var type = typeof (Student);
var prop = type.GetMethod("get_Name");
var il = dm.GetILGenerator();
il.Emit(OpCodes.Ldarg_0);
il.Emit(OpCodes.Call, prop);
il.Emit(OpCodes.Ret);
return (Func<Student, string>)dm.CreateDelegate(typeof(Func<Student, string>));
}
static Func<Student, string> ExpressionGetter()
{
var type = typeof(Student);
var prop = type.GetMethod("get_Name");
ParameterExpression pa = Expression.Parameter(typeof(Student));
Expression body = Expression.Call(pa, prop);
return Expression.Lambda<Func<Student, string>>(body, pa).Compile();
}
static Func<Student, string> DynamicGetter()
{
return s => { dynamic d = s; return d.Name; };
}
[MethodImpl(MethodImplOptions.NoOptimization)]
public static void Run()
{
const int loop = 5000000;
var stu = new Student {Name = "Mike"};
var dynamic =
Test(loop, stu, DynamicGetter());
var expression =
Test(loop, stu, ExpressionGetter());
var native =
Test(loop, stu, NativeGetter());
var emitted =
Test(loop, stu, EmittedGetter());
var reflected =
Test(loop, stu, ReflectedGetter());
Console.WriteLine("native:{0}\ndynamic:{1}\nemit:{2}\nexpression:{3}\nreflection:{4}", 1, dynamic / native, emitted / native, expression / native, reflected / native);
Console.ReadKey();
}
测试结果
1. 当循环次数比较小的时候, loop=1000
native:1
dynamic:540.444964871194
emit:0.704918032786885
expression:0.224824355971897
reflection:8.37002341920375
2. loop=5000000
native:1
dynamic:4.37328053807767
emit:0.96159470600998
expression:1.00412887828162
reflection:35.909097418095
当跨assemblies的时候要特别注意两者的区别, 请看这篇文章
if the scope of your constant is limited to just one assembly, class, or smaller (you can define a const inside a method), this is not a big deal. However, if the const is visible outside the assembly it is defined in, we must be wary! Because the const’s value is substituted at compile time, this means that if the assembly that defines the const changes its value, but the calling assembly isn’t recompiled, then the calling assembly will still see the original value.Let’s illustrate. Assume a class library called Shapes.DLL that defines this:
1: public class Circle
2: {
3: public const double Pi = 3.14;
4:
5: // ...
6: }
Now let’s assume a separate program called Drawing.EXE adds a reference to Shapes.DLL and uses the const:
1: public static class Drawing
2: {
3: public static void Main()
4: {
5: Console.WriteLine(“Pi is: “ + Circle.Pi);
6: }
7: }
If we run this, we get:
1: Pi is 3.14
Now let’s say during the QA process someone decides that this value of Pi is not precise enough and changes the definition:
1: public const double Pi = 3.1415927;
And they rebuild the Shapes.DLL and just drop it into the deployment directory for Drawing.EXE without rebuilding it. What happens if we run Drawing.EXE again without recompiling? We get:
1: Pi is 3.14
Whoa! Even though we changed the value of Pi in our referenced assembly and deployed it to where Drawing.EXE expected it and Drawing.EXE loaded it, it still prints 3.14. This is because const is a compile-time substitution. Thus, if you change the value of a const, it will not be picked up until the code using it is recompiled as well. If we recompile and run Drawing.EXE, we will get:
1: Pi is 3.1415927
Thus, const should be used mainly for values that are not subject to change, or freely if the scope of the const is limited to the same assembly or smaller.
在sqlserver中可以这样显示分组前N个成员, 关键在row_number, partition
select * from
(select schoolmember_id, row_number() over(partition by school_id order by schoolmember_id ) as number from schoolmember) as a
where a.number < 3
private static int BinarySearch(T[] array, int index, int length, T value)
{
int lo = index;
int hi = index + length - 1;
while (lo <= hi)
{
int i = lo + ((hi - lo) >> 1);
int order;
if (array[i] == null)
{
order = (value == null) ? 0 : -1;
}
else
{
order = array[i].CompareTo(value);
}
if (order == 0)
{
return i;
}
if (order < 0)
{
lo = i + 1;
}
else
{
hi = i - 1;
}
}
return ~lo;
}
最后一手~lo精妙。如果找不到value。当hi = lo + 1时。
1.如果value > lo。必然发生lo = lo + 1。~~lo落在插入点。
2.如果value < lo。必然发生lo。~~lo依然落在插入点上。
证毕