2010-12-03 2 views
14

В C# мне кажется, что нет функции «Math.Cos», которая возвращает float. Двойное значение - это единственное значение, которое вы можете вернуть, тем самым вынуждая его использовать его для поплавка. Как так:
float val = (float)Math.Cos(someVal);Может ли «System.Math.Cos» возвращать (плавать)?

мне нужно использовать поплавки, потому что я делаю вещи в Direct3D, который строго использует поплавки. Поплавки гораздо чаще встречаются в мире графики (как сейчас), потому что они 32 бит.

Есть ли какая-либо функциональность внутри C#, которую я могу использовать, просто будет обрабатывать поплавки, например C++?

Я не хочу обертывать какие-либо материалы на C++, потому что это нужно запускать на XNA & Linux для OpenGL.

ПРИМЕЧАНИЕ: Было бы неплохо иметь код, в котором не было бы двойного поплавка.

+3

Вы можете перегрузить math.cos() с вашей собственной версией, которая просто возвращает литую версию. – Puppy 2010-12-03 21:36:59

+1

Хотя Direct3D требует поплавков, все равно лучше работать с двойным, пока вам не придется конвертировать, поскольку он позволяет избежать проблем с округлением ошибок (но не всех). – ChrisF 2010-12-03 21:45:14

+4

@ChrisF - это действительно не так с играми. Округление редко бывает проблемой или может быть устранено путем зажима, а первичная экономия на избежании двойного значения является значительной. – codekaizen 2010-12-03 21:47:44

ответ

6

Не вдаваясь в какую-то углубленную математику, вы не сможете написать свой собственный точный Функция Cos. Вот предложение, хотя с помощью метода расширения:

class Program 
{ 
    static void Main(string[] args) 
    { 
     float cos = Math.Cos(.25d).ToFloat(); 

     Console.WriteLine("cos(.25d) = {0}", cos); 

     Console.ReadKey(); 
    } 
} 

public static class MathExtensions 
{ 
    public static float ToFloat(this double value) 
    { 
     return (float)value; 
    } 
} 

Это еще один способ использования Func<T, TResult> и создать свой собственный MathF статический класс:

class Program 
{ 
    static void Main(string[] args) 
    { 
     Console.WriteLine("cos(.25d) = {0}", MathF.Cos(.25d)); 
     Console.WriteLine("sin(.25d) = {0}", MathF.Sin(.25d)); 

     Console.ReadKey(); 
    } 
} 

public static class MathF 
{ 
    public static Func<double, float> Cos = angleR => (float)Math.Cos(angleR); 
    public static Func<double, float> Sin = angleR => (float)Math.Sin(angleR); 
} 

Как уже отмечалось, делегаты Func будет медленнее, zezba подтвердил в своем тестовом коде (я не знал, что делегаты будут намного медленнее). Самый быстрый - это прямой бросок для плавания. Средней стороной были бы простые вызовы статических методов в статическом классе MathF.

4

Я бы создал класс MathCommonMethods с методами, которые бы преобразовывали все часто используемые типы возвращаемых данных в плавающие в leiu двойников. Это сэкономит вам некоторую типизацию в долгосрочной перспективе.

Насколько существует существующая функция, возвращающая значение в качестве поплавка, я не слышал об этом.

Вы также должны быть осторожны при бросании, чтобы не потерять точность, если точность важна для вашего приложения.

2

Если вы хотите избежать кастинга, вам понадобится другая реализация. Если вы делаете кросс-платформу, вы можете создать слой абстракции платформы, где вы можете поместить различные реализации на платформе. Это поможет в производительности. Если перфоманс не является проблемой (это всегда имеет место в играх), то создание функции полезности и выполнение кастинга есть хорошее решение.

3

Хорошо, поэтому я запустил несколько тестов, чтобы узнать, какой метод был самым быстрым после чтения «dboarman». К сожалению, это не так, как можно сделать без кастинга, используя строго C# &. Самый быстрый способ - просто бросить на место, так что я забочусь о скорости, поскольку в основном для игр плохо придерживаться старого метода литья.

Эти тесты были составлены с использованием следующих спецификаций ::

C# .NET 4.0 
ConsoleApplication - Release - Optimized code - x64 
4gb ram, 2.4ghz AMD_X2_DualCore 4600 CPU, running Windows7 Ultimate. 

Код:

static void Main(string[] args) 
{ 
    //Start 
    Console.Write("Hit Enter to Start\n"); 
    Console.ReadLine(); 
    long num = 100; 
    long mil = 0; 
    float val = 0.01f; 
    Stopwatch startTime = new Stopwatch(); 

    //Run 
    for(long i = 0; i != num; ++i) 
    { 
     startTime.Restart(); 
     for(uint i2 = 0; i2 != 1000000; ++i2) val = (float)System.Math.Cos(val);// 48 Milliseconds 
     //for(uint i2 = 0; i2 != 1000000; ++i2) val = System.Math.Cos(val).ToFloat();// 53 Milliseconds 
     //for(uint i2 = 0; i2 != 1000000; ++i2) val = MathF2.Cos(val);// 59 Milliseconds 
     //for(uint i2 = 0; i2 != 1000000; ++i2) val = MathF.Cos(val);// 63 Milliseconds 
     startTime.Stop(); 
     mil += startTime.ElapsedMilliseconds; 
    } 

    //End 
    mil /= num; 

    //Print 
    Console.Write("Milliseconds = "+mil.ToString()); 
    Console.ReadLine(); 
} 

Вот базовый математический код для испытаний ::

public static class MathF 
{ 
    public static Func<double, float> Cos = angleR => (float)System.Math.Cos(angleR); 
    public static Func<double, float> Sin = angleR => (float)System.Math.Sin(angleR); 
} 

public static class MathF2 
{ 
    public static float Cos(float pValue) {return (float)System.Math.Cos(pValue);} 
} 

public static class MathExtensions 
{ 
    public static float ToFloat(this double value) 
    { 
     return (float)value; 
    } 
} 
Смежные вопросы