Как вручную разобрать число с плавающей запятой из строки

Более быстрые результаты могут быть достигнуты с помощью numpy.where .

Например, при настройке unubtu -

In [76]: df.iloc[np.where(df.A.values=='foo')]
Out[76]: 
     A      B  C   D
0  foo    one  0   0
2  foo    two  2   4
4  foo    two  4   8
6  foo    one  6  12
7  foo  three  7  14

Сроки сравнения:

In [68]: %timeit df.iloc[np.where(df.A.values=='foo')]  # fastest
1000 loops, best of 3: 380 µs per loop

In [69]: %timeit df.loc[df['A'] == 'foo']
1000 loops, best of 3: 745 µs per loop

In [71]: %timeit df.loc[df['A'].isin(['foo'])]
1000 loops, best of 3: 562 µs per loop

In [72]: %timeit df[df.A=='foo']
1000 loops, best of 3: 796 µs per loop

In [74]: %timeit df.query('(A=="foo")')  # slowest
1000 loops, best of 3: 1.71 ms per loop

29
задан Thomas 17 September 2008 в 16:48
поделиться

9 ответов

Я непосредственно собрал бы число с плавающей точкой с помощью его двоичного представления.

Read в символе номер один за другим и сначала находят все цифры. Сделайте это в целочисленной арифметике. Также отслеживайте десятичную точку и экспоненту. Этот будет важен позже.

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

биты сразу после первого одноразрядного являются Вашей мантиссой.

Получение экспоненты не трудно также. Вы знаете первое одноразрядное положение, положение десятичной точки и дополнительной экспоненты от экспоненциального представления. Объедините их и добавьте смещение экспоненты с плавающей точкой (я думаю, что это 127, но проверьте некоторую ссылку).

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

Хранилище экспонента как он в биты 24 - 30 из Вашего плавания.

старший значащий бит является просто знаком. Каждый имеет в виду отрицательные, нулевые положительные средства.

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

Btw - выполнение арифметики в самой плавающей точке является плохой идеей, потому что Вы будете всегда вынуждать свою мантиссу быть усеченной к 23 значимым битам. Вы не получите точное представление тот путь.

11
ответ дан Pascal Cuoq 17 September 2008 в 16:48
поделиться
  • 1
    Это работало с 2,1. Однако документация еще не была обновлена updater опция. Я отправляю запрос получения по запросу теперь – Trung Lê 15 October 2012 в 00:43

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

, Если Вы не боитесь математики, я настоятельно рекомендую чтение следующей статьи David Goldberg, , Что Каждый Программист Должен Знать Об Арифметике С плавающей точкой . Вы получите лучшее понимание для того, что продолжается под капотом, и почему биты размечаются как таковые.

Мой лучший совет состоит в том, чтобы запустить с работы atoi реализацию и съехать оттуда. Вы быстро найдете пропавших без вести вещей но несколько взглядов источник strtod и Вы будете на правильном пути (который является долгим, длинным трактом). В конечном счете Вы похвалите , вводят божество здесь , что существуют стандартные библиотеки.

/* use this to start your atof implementation */

/* atoi - christopher.watford@gmail.com */
/* PUBLIC DOMAIN */
long atoi(const char *value) {
  unsigned long ival = 0, c, n = 1, i = 0, oval;
  for( ; c = value[i]; ++i) /* chomp leading spaces */
    if(!isspace(c)) break;
  if(c == '-' || c == '+') { /* chomp sign */
    n = (c != '-' ? n : -1);
    i++;
  }
  while(c = value[i++]) { /* parse number */
    if(!isdigit(c)) return 0;
    ival = (ival * 10) + (c - '0'); /* mult/accum */
    if((n > 0 && ival > LONG_MAX)
    || (n < 0 && ival > (LONG_MAX + 1UL))) {
      /* report overflow/underflow */
      errno = ERANGE;
      return (n > 0 ? LONG_MAX : LONG_MIN);
    }
  }
  return (n>0 ? (long)ival : -(long)ival);
}
22
ответ дан Rakete1111 17 September 2008 в 16:48
поделиться
  • 1
    Я провел часы, преследуя вокруг с перестановками ' typeahead:selected' событие без результатов. Но это на самом деле работало, СПАСИБО... – makak 16 May 2016 в 04:43

Вы могли проигнорировать десятичное число при парсинге (за исключением его местоположения). Скажите, что вход был: 156.7834e10... Это могло легко быть проанализировано в целое число 1 567 834 сопровождаемых e10, который Вы тогда измените к e6, так как десятичное число было 4 цифрами от конца части "цифры" плавания.

Точность является проблемой. Необходимо будет проверить спецификацию IEEE языка, который Вы используете. Если число битов в Мантиссе (или Часть) будет больше, чем число битов в Вашем Целом типе, то Вы возможно потеряете точность, когда кто-то введет в числе, таком как:

5123.123123e0 - преобразовывает в 5123123123 в нашем методе, который НЕ помещается в Целое число, но биты для 5,123123123 могут поместиться в мантиссу спецификации плавающей.

, Конечно, Вы могли использовать метод, который берет каждую цифру перед десятичным числом, умножает текущее общее количество (в плавании) на 10, затем добавляет новую цифру. Для цифр после десятичного числа умножьте цифру на растущую мощь 10 прежде, чем добавить к текущему общему количеству. Этот метод, кажется, уклоняется от предмета спора того, почему Вы делаете это вообще, однако, поскольку он требует использования примитива с плавающей точкой, не пользуясь легко доступными библиотеками парсинга.

Так или иначе, удачи!

2
ответ дан billjamesdev 17 September 2008 в 16:48
поделиться

"Стандартным" алгоритмом для преобразования десятичного числа к лучшему приближению с плавающей точкой является William Clinger , Как считать числа с плавающей точкой точно , загружаемый от здесь . Обратите внимание, что выполнение этого правильно требует целых чисел многократно увеличенной точности, по крайней мере, определенного процента времени, для обработки угловых случаев.

Алгоритмы для того, чтобы пойти другим путем, печатая лучшее десятичное число от плавающего числа, найдены в Бургере и Dybvig Числа с плавающей запятой Печати Быстро и Точно , загружаемыми здесь . Это также требует, чтобы целочисленная арифметика многократно увеличенной точности

Видела также David M Гей Правильно Округленные Двоично-десятичные и Десятично-двоичные Преобразования для алгоритмов, идущих обоими путями.

19
ответ дан Peter S. Housel 17 September 2008 в 16:48
поделиться

Для этого необходимо понять стандартный IEEE 754 для надлежащего двоичного представления. После этого можно использовать Float.intBitsToFloat или Double.longBitsToDouble.

http://en.wikipedia.org/wiki/IEEE_754

0
ответ дан Jorge Ferreira 17 September 2008 в 16:48
поделиться
  • 1
    этот doesn' t работают в последней версии ввода с опережением – Matthew Lock 7 September 2018 в 10:01

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

0
ответ дан Adam Rosenfield 17 September 2008 в 16:48
поделиться
  • 1
    К сожалению, это не работает на меня. Когда я делаю это Ваш предложенный путь, вторая опция не стреляет. Двойной ' on' кажется более безопасным. – Jeffz 6 January 2019 в 19:05

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

-1
ответ дан terminus 17 September 2008 в 16:48
поделиться

Не возможно преобразовать любую произвольную строку, представляющую число в двойное или плавание, не теряя точность. Существует много дробных чисел, которые могут быть представлены точно в десятичном числе (например, "0.1"), который может только быть приближен в двоичном плавании или дважды. Это подобно тому, как часть 1/3 не может быть представлена точно в десятичном числе, можно только записать 0.333333...

, Если Вы не хотите использовать библиотечную функцию непосредственно, почему бы не посмотреть на исходный код для тех библиотечных функций? Вы упомянули Java; большинство JDKs поставлется с исходным кодом для библиотек классов, таким образом, Вы могли искать как java.lang. Double.parseDouble (Строка) работы метода. Конечно, что-то как BigDecimal лучше для управления точностью и округления режимов, но Вы сказали, что это должно быть плавание или дважды.

0
ответ дан sk. 17 September 2008 в 16:48
поделиться

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

Проблема нетривиальна.

Я инженер по аппаратному обеспечению, заинтересованный в разработке оборудования с плавающей запятой. Я работаю над своей второй реализацией.

Я нашел это сегодня http://speleotrove.com/decimal/decarith.pdf

, где на странице 18 приведены некоторые интересные тестовые примеры.

Да, у меня есть прочитал статью Клингера, но, будучи простым инженером по аппаратному обеспечению, я не мог осмыслить представленный код. Ссылка на алгоритм Стила, как это дано в Knuth ' текст был мне полезен. Как ввод, так и вывод проблематичны.

Все вышеупомянутые ссылки на различные статьи превосходны.

Я еще не подписался здесь, но когда я это сделаю, предполагая, что логин не будет выполнен, это будет broh . (бро-точка).

Клайд

-1
ответ дан 27 November 2019 в 22:15
поделиться
Другие вопросы по тегам:

Похожие вопросы: