К сожалению, нет эквивалента c, не требующего скомпилированной внешней зависимости. В зависимости от ваших потребностей, суть, которую я сделал: https://gist.github.com/mscuthbert/f22942537ebbba2c31d4 может помочь.
Он предоставляет функцию opFrac(num)
, которая необязательно преобразует int, float или Fraction в float или Fraction с пределом знаменателя (я использую 65535, потому что я работаю с небольшими дробями); если число с плавающей точкой может быть точно представлено в двоичном виде (то есть это кратное некоторой степени двух знаменатель), оно оставляет его в покое. В противном случае он преобразует его в дробь. Точно так же, если фракция точно представлена в двоичном виде, мы конвертируем ее в число с плавающей точкой; в противном случае мы оставляем это в покое.
Вызов Fraction(float).limit_denominator(x)
извлекается во вспомогательную функцию _preFracLimitDenominator
, которая создает только один объект Fraction
, а не три, обычно создаваемые с помощью вызова.
Вариантов использования этой сущности довольно мало, но там, где они существуют, результаты впечатляют. Для моего проекта music21 мы работаем в основном с нотами, которые обычно помещаются в такт (целое число) или в половину, четверть, восьмой и т. Д. (Точно представимые в двоичном виде), но в более редких случаях, когда заметки располагаются ( смещение) или длительность, скажем, 1/3 или 1/5 доли, мы столкнулись с большими проблемами преобразования с плавающей запятой, которые привели к неясным ошибкам. Наш тестовый набор выполнялся за 350 секунд с использованием смещений и длительностей с плавающей запятой. Переключение всего на дроби увеличило время до 1100 секунд - совершенно недопустимо. Переход к дополнительным фракциям с быстрым созданием фракций вернул время к 360 секундам, или только к 3% снижению производительности.
Если вы можете иметь дело с работой с плавающей точкой, а иногда с дробями, это может быть путь.