Подтвердить что ты не робот

Самый быстрый способ преобразования объекта в двойное?

Каков самый быстрый способ преобразования объекта в double? Я сейчас нахожусь в коде, который гласит:

var d = double.TryParse(o.ToString(), out d);  // o is the Object...

Первые мысли заключались в том, чтобы переписать это как

var d = Convert.ToDouble(o);

но будет ли это на самом деле быстрее?

EDIT: В дополнение к запуску профиля (кстати, я настоятельно рекомендую JetBrains dotTrace для любого разработчика), я запустил Reflector, и это помогло мне прийти (более или менее соответствующая часть кода):

if (o is IConvertible)
{
    d = ((IConvertible)o).ToDouble(null);
}
else
{
    d = 0d;
}

Исходный код double.TryParse() выполнен в 140 мс. Новый код выполняется в 34 мс. Я почти уверен, что это путь оптимизации, который я должен предпринять, но прежде чем я это сделаю, кто-нибудь видит что-то проблематичное с моим "оптимизированным" кодом? Заранее благодарим за ваши отзывы!

4b9b3361

Ответ 1

Вы должны делать целую колоссальную сумму, чтобы иметь смысл потратить на это какое-то время. Однако меня здесь не судить:

Итак, ваш код таков:

if (o is IConvertible)
{
    d = ((IConvertible)o).ToDouble(null);
}
else
{
    d = 0d;
}

Интересно, будет ли вам лучше с этим

IConvertible convert = o as IConvertible;

if (convert != null)
{
  d = convert.ToDouble(null);
}
else
{
  d = 0d;
}

Сохраняет двойное нажатие.

Ответ 2

Я пробовал следующие методы.

  • double.TryParse
  • double.Parse
  • Convert.ToDouble

Я использовал следующий код.

public static void Main()
{
    string text = "3.14";
    var timer = new Stopwatch();
    timer.Start();
    for (int i = 0; i < 10000000; i++)
    {
        double d;
        d = Convert.ToDouble(text);
        //double.TryParse(text, out d);
        //d = double.Parse(text);
    }
    timer.Stop();
    Console.WriteLine("Time=" + timer.Elapsed.ToString());
    Console.ReadLine();
}

На моей машине я увидел эти результаты. Я усреднил 3 разных прогона.

  • double.TryParse = 4.45 секунд
  • double.Parse = 4.45 секунд
  • Convert.ToDouble = 4.75 секунд

Конечно, я использовал строку, которая была конвертируемой. Если строка не конвертируема, то я очень подозреваю, что double.TryParse будет самым быстрым на длинный снимок.

Ответ 3

Создайте небольшое тестовое приложение, используя System.Diagnostics.Stopwatch и узнайте, что происходит быстрее. Хотя я бы сказал, что это не будет иметь смысл. Я бы пошел на Convert.ToDouble исключительно для удобочитаемости.

Ответ 4

Во-первых, если вы действительно хотите узнать, что быстрее, вы должны написать быстрый тест (используя данные, которые вы ожидаете для обработки) и время каждой опции. Не зная, что o (или, вероятно, будет), очень трудно судить. Я подозреваю, что вы не увидите большой разницы.

Во-вторых, если вы не назовете этот бит кода в чрезвычайно критичной для времени части вашего кода и называя его тысячами времени для загрузки, я сомневаюсь, что это действительно имеет значение. Напишите хороший, чистый код, а затем оптимизируйте.

Ответ 5

Есть несколько разных вещей, которые вы могли бы попытаться сделать, в зависимости от того, что это такое. Это может быть

a) двойное двойное число, и вы просто хотите его удалить:

object o = 53.2;
double d = (double)o;

b) некоторый другой тип, значение или ссылка, которая имеет некоторое преобразование в двойное доступное (реализует IConvertible.ToDouble()), который вы хотите использовать

object o = 53.2M; // a System.Decimal
double d = Convert.ToDouble(o);

или

c) то, что имеет строковое представление по умолчанию, которое может быть проанализировано как двойное

object o = "53.2";
double d;
bool convertedOK = double.TryParse(o.ToString(), out d);

Вариант c, в некотором смысле, самый длинный путь; вы берете свой объект, запрашивая его строковое представление, а затем пытаетесь разобрать эту строку, чтобы получить двойной. Это неудобно, если вам не нужно это делать, и в вашем примере из 40 000 звонков он собирается создавать и удалять 40 000 строк...

Если вы знаете, что ваш объект всегда будет содержать что-то, что реализует преобразование в double, вы можете пропустить все это и перейти к опции b. И если вы знаете, что ваш объект будет просто двойным в штучной упаковке, попробуйте простейший вариант (a) просто удалить его.

Возможно, что-то в этом направлении будет работать для вас, если вы действительно не знаете, что будет?

double d = (o is double) ? (double)o
    : (o is IConvertible) ? (o as IConvertible).ToDouble(null)
    : double.Parse(o.ToString());

(обратите внимание: это не будет работать, если o содержит что-то, что реализует IConvertible, но не может быть преобразовано в double, или если его строковое представление не может быть проанализировано как double)

Я ничего не говорил об относительных скоростях, но я был бы поражен, если бы распаковка была существенно быстрее, чем преобразование в строку, а затем синтаксический анализ (если оптимизатор не сумасшедший умный).

Быстрый тест в LINQPad с использованием секундомера .NET предлагает большую разницу.

IEnumerable<object> myData = new List<object>() { "53.2", 53.2M, 53.2D };
const int iterations = 10000000;
var sw = new Stopwatch();
var results = new List<string>();

foreach (var o in myData)
{
    sw.Reset();
    sw.Start();

    for (var i=0; i < iterations; i++)
    {
        double d = (o is double) ? (double)o
            : (o is IConvertible) ? (o as IConvertible).ToDouble(null)
            : double.Parse(o.ToString());
    }

    sw.Stop();

    results.Add($"{o.GetType()}: {iterations} iterations took {sw.ElapsedMilliseconds}ms");
}

results.Dump();

на моем ПК дает следующие результаты

System.String: 10000000 iterations took 1329ms 
System.Decimal: 10000000 iterations took 402ms 
System.Double: 10000000 iterations took 38ms