Может ли "System.Math.Cos" возвращать (float)?

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

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

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

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

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

Ответы

Ответ 1

Не вдаваясь в какую-то углубленную математику, вы не сможете написать свою собственную точную функцию 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.

Ответ 2

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

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

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

Ответ 3

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

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

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;
    }
}

Ответ 4

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