Merge pull request #5767 from pchote/isqrt

Add Exts.ISqrt to avoid fp sqrt calculations.
This commit is contained in:
Matthias Mailänder
2014-07-04 15:48:20 +02:00
6 changed files with 93 additions and 7 deletions

View File

@@ -42,7 +42,7 @@ namespace OpenRA
public CVec Sign() { return new CVec(Math.Sign(X), Math.Sign(Y)); } public CVec Sign() { return new CVec(Math.Sign(X), Math.Sign(Y)); }
public CVec Abs() { return new CVec(Math.Abs(X), Math.Abs(Y)); } public CVec Abs() { return new CVec(Math.Abs(X), Math.Abs(Y)); }
public int LengthSquared { get { return X * X + Y * Y; } } public int LengthSquared { get { return X * X + Y * Y; } }
public int Length { get { return (int)Math.Sqrt(LengthSquared); } } public int Length { get { return Exts.ISqrt(LengthSquared); } }
public CVec Clamp(Rectangle r) public CVec Clamp(Rectangle r)
{ {

View File

@@ -202,6 +202,91 @@ namespace OpenRA
public static Size NextPowerOf2(this Size s) { return new Size(NextPowerOf2(s.Width), NextPowerOf2(s.Height)); } public static Size NextPowerOf2(this Size s) { return new Size(NextPowerOf2(s.Width), NextPowerOf2(s.Height)); }
public enum ISqrtRoundMode { Floor, Nearest, Ceiling }
public static int ISqrt(int number, ISqrtRoundMode round = ISqrtRoundMode.Floor)
{
if (number < 0)
throw new InvalidOperationException("Attempted to calculate the square root of a negative integer: {0}".F(number));
return (int)ISqrt((uint)number, round);
}
public static uint ISqrt(uint number, ISqrtRoundMode round = ISqrtRoundMode.Floor)
{
var divisor = 1U << 30;
var root = 0U;
var remainder = number;
// Find the highest term in the divisor
while (divisor > number)
divisor >>= 2;
// Evaluate the root, two bits at a time
while (divisor != 0)
{
if (root + divisor <= remainder)
{
remainder -= root + divisor;
root += 2 * divisor;
}
root >>= 1;
divisor >>= 2;
}
// Adjust for other rounding modes
if (round == ISqrtRoundMode.Nearest && remainder > root)
root += 1;
else if (round == ISqrtRoundMode.Ceiling && root * root < number)
root += 1;
return root;
}
public static long ISqrt(long number, ISqrtRoundMode round = ISqrtRoundMode.Floor)
{
if (number < 0)
throw new InvalidOperationException("Attempted to calculate the square root of a negative integer: {0}".F(number));
return (long)ISqrt((ulong)number, round);
}
public static ulong ISqrt(ulong number, ISqrtRoundMode round = ISqrtRoundMode.Floor)
{
var divisor = 1UL << 62;
var root = 0UL;
var remainder = number;
// Find the highest term in the divisor
while (divisor > number)
divisor >>= 2;
// Evaluate the root, two bits at a time
while (divisor != 0)
{
if (root + divisor <= remainder)
{
remainder -= root + divisor;
root += 2 * divisor;
}
root >>= 1;
divisor >>= 2;
}
// Adjust for other rounding modes
if (round == ISqrtRoundMode.Nearest && remainder > root)
root += 1;
else if (round == ISqrtRoundMode.Ceiling && root * root < number)
root += 1;
return root;
}
public static string JoinWith<T>(this IEnumerable<T> ts, string j) public static string JoinWith<T>(this IEnumerable<T> ts, string j)
{ {
return string.Join(j, ts); return string.Join(j, ts);

View File

@@ -1,6 +1,6 @@
#region Copyright & License Information #region Copyright & License Information
/* /*
* Copyright 2007-2011 The OpenRA Developers (see AUTHORS) * Copyright 2007-2014 The OpenRA Developers (see AUTHORS)
* This file is part of OpenRA, which is free software. It is made * This file is part of OpenRA, which is free software. It is made
* available to you under the terms of the GNU General Public License * available to you under the terms of the GNU General Public License
* as published by the Free Software Foundation. For more information, * as published by the Free Software Foundation. For more information,
@@ -8,6 +8,7 @@
*/ */
#endregion #endregion
using System;
using System.Drawing; using System.Drawing;
namespace OpenRA.Graphics namespace OpenRA.Graphics
@@ -98,7 +99,7 @@ namespace OpenRA.Graphics
var yc = (r.Bottom + r.Top) / 2; var yc = (r.Bottom + r.Top) / 2;
for (var y = r.Top; y <= r.Bottom; y++) for (var y = r.Top; y <= r.Bottom; y++)
{ {
var dx = a * System.Convert.ToSingle(System.Math.Sqrt(1 - (y - yc) * (y - yc) / b / b)); var dx = a * (float)(Math.Sqrt(1 - (y - yc) * (y - yc) / b / b));
DrawLine(new float2(xc - dx, y), new float2(xc + dx, y), color, color); DrawLine(new float2(xc - dx, y), new float2(xc + dx, y), color, color);
} }
} }

View File

@@ -712,7 +712,7 @@ namespace OpenRA
for (var j = -max; j <= max; j++) for (var j = -max; j <= max; j++)
for (var i = -max; i <= max; i++) for (var i = -max; i <= max; i++)
if (max * max >= i * i + j * j) if (max * max >= i * i + j * j)
ts [(int)Math.Ceiling(Math.Sqrt(i * i + j * j))].Add(new CVec(i, j)); ts [Exts.ISqrt(i * i + j * j, Exts.ISqrtRoundMode.Ceiling)].Add(new CVec(i, j));
// Sort each integer-distance group by the actual distance // Sort each integer-distance group by the actual distance
foreach (var list in ts) foreach (var list in ts)

View File

@@ -35,7 +35,7 @@ namespace OpenRA
public int2 Sign() { return new int2(Math.Sign(X), Math.Sign(Y)); } public int2 Sign() { return new int2(Math.Sign(X), Math.Sign(Y)); }
public int2 Abs() { return new int2(Math.Abs(X), Math.Abs(Y)); } public int2 Abs() { return new int2(Math.Abs(X), Math.Abs(Y)); }
public int LengthSquared { get { return X * X + Y * Y; } } public int LengthSquared { get { return X * X + Y * Y; } }
public int Length { get { return (int)Math.Sqrt(LengthSquared); } } public int Length { get { return Exts.ISqrt(LengthSquared); } }
public override int GetHashCode() { return X.GetHashCode() ^ Y.GetHashCode(); } public override int GetHashCode() { return X.GetHashCode() ^ Y.GetHashCode(); }
public static int2 Max(int2 a, int2 b) { return new int2(Math.Max(a.X, b.X), Math.Max(a.Y, b.Y)); } public static int2 Max(int2 a, int2 b) { return new int2(Math.Max(a.X, b.X), Math.Max(a.Y, b.Y)); }

View File

@@ -37,9 +37,9 @@ namespace OpenRA
public static int Dot(WVec a, WVec b) { return a.X * b.X + a.Y * b.Y + a.Z * b.Z; } public static int Dot(WVec a, WVec b) { return a.X * b.X + a.Y * b.Y + a.Z * b.Z; }
public long LengthSquared { get { return (long)X * X + (long)Y * Y + (long)Z * Z; } } public long LengthSquared { get { return (long)X * X + (long)Y * Y + (long)Z * Z; } }
public int Length { get { return (int)Math.Sqrt(LengthSquared); } } public int Length { get { return (int)Exts.ISqrt(LengthSquared); } }
public long HorizontalLengthSquared { get { return (long)X * X + (long)Y * Y; } } public long HorizontalLengthSquared { get { return (long)X * X + (long)Y * Y; } }
public int HorizontalLength { get { return (int)Math.Sqrt(HorizontalLengthSquared); } } public int HorizontalLength { get { return (int)Exts.ISqrt(HorizontalLengthSquared); } }
public WVec Rotate(WRot rot) public WVec Rotate(WRot rot)
{ {