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

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

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

Например,3.1415926535... приведет к245/78, скорее, чем314/100 или же .22/7

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

 pavium01 нояб. 2009 г., 12:50
245/78 - лучшее приближение к PI с числителем и знаменателем байтового размера.
 Eric01 нояб. 2009 г., 17:43
Обратите внимание, что Java-байты подписаны, поэтому 245 isn 'значение байта в Java " - Упс. Думаю, я хотел неподписанные байты
 Eric01 нояб. 2009 г., 12:53
К сожалению. Хорошая точка зрения.
 uckelman01 нояб. 2009 г., 14:27
Это должно быть помечено "математика», Я'Я бы сделал это сам, но я нене имею достаточной репутации. "
 starblue01 нояб. 2009 г., 12:58
Обратите внимание, что Java-байты подписаны, поэтому 245 isn 'значение байта в Java.

Ответы на вопрос(6)

s код, который я использовал в конце (на основе uckelman 'с кодом)

public static int[] GetFraction(double input)
{
    int p0 = 1;
    int q0 = 0;
    int p1 = (int) Math.floor(input);
    int q1 = 1;
    int p2;
    int q2;

    double r = input - p1;
    double next_cf;
    while(true)
    {
        r = 1.0 / r;
        next_cf = Math.floor(r);
        p2 = (int) (next_cf * p1 + p0);
        q2 = (int) (next_cf * q1 + q0);

        // Limit the numerator and denominator to be 256 or less
        if(p2 > 256 || q2 > 256)
            break;

        // remember the last two fractions
        p0 = p1;
        p1 = p2;
        q0 = q1;
        q1 = q2;

        r -= next_cf;
    }

    input = (double) p1 / q1;
    // hard upper and lower bounds for ratio
    if(input > 256.0)
    {
        p1 = 256;
        q1 = 1;
    }
    else if(input < 1.0 / 256.0)
    {
        p1 = 1;
        q1 = 256;
    }
    return new int[] {p1, q1};
}

Спасибо за тех, кто помог

 Echsecutor05 окт. 2017 г., 23:30
То есть вы используете конвергенты непрерывных дробей.en.wikipedia.org/wiki/... Это дает некоторое приближение, но почему оно должно быть оптимальным в данном диапазоне числителей / знаменателей?

с BigFraction:

import org.apache.commons.math3.fraction.BigFraction;

public static BigFraction GetBigFraction(double input)
{
    int precision = 1000000000;
    return new BigFraction((int)(input * (double)precision), precision);
}

Эрик»ответ выше неРассмотрим случай, когда возможен точный результат. Например, если вы используете 0,4 в качестве входных данных, тогда представление должно быть 2/5, и в этом случае вы получите деление на ноль в третьей итерации цикла (r = 0 во втором цикле => r = 1 / r ошибка на третьем).

Итак, вы хотите изменить цикл while, чтобы исключить эту опцию:

while(true)

должно быть

while(r != 0)



Учитывая ограничение на знаменатель d, последовательность Фареи - это каждая дробь, имеющая знаменатель <= г

Затем вы просто возьмете свой поплавок и сравните его с разрешенным значением доли Фари. Это позволит вам представить ваш float с точки зрения повторяющихся десятичных чисел.

Вот страница о его реализации в Java:

http://www.merriampark.com/fractions.htm

Вот хорошая демонстрация их использования:

http://www.maths.surrey.ac.uk/hosted-sites/R.Knott/Fractions/fareySB.html

Решение Вопроса

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

Вы можете найти мой кодВотв методе updateRatio (), начинающемся со строки 1161. Вы можете просто использовать его, если у вас работает лицензия LGPL. То, что я сделал, по существу следует тому, чтосделано в GIMP --- это одна из тех вещей, где естьЭто всего лишь один эффективный и разумный способ сделать это.

если вы не вызываете эту функцию преобразования 100 или более раз в секунду, то она, вероятно, не будетне так уж трудно перебрать все возможные знаменатели (наиболее вероятно, только 255 из них) и найти, какой из них дает наиболее близкое приближение (вычисление числителя для работы со знаменателем является постоянным временем).

 Thorbjørn Ravn Andersen01 нояб. 2009 г., 14:36
Это лучше, чем подход с непрерывной дробью, поскольку вы ограничены байтовыми значениями.
 Joey01 нояб. 2009 г., 13:30
аааа, верно. Все еще слишком рано сегодня, извините.
 Eric01 нояб. 2009 г., 12:42
Эффективность неэто действительно проблема. Однако я надеялся (и смутно припоминаю), что есть метод, который более эффективен, чем грубая сила.
 Amber01 нояб. 2009 г., 13:11
Нет, ты неЙоханнес - учитывая конкретный знаменатель, вы можете вычислить ближайший числитель напрямую - поскольку вы хотите, чтобы A и B были такими, что A / B = C, вы просто вычисляете B * C и округляете до ближайшего целого числа, и это ваш числитель.

Ваш ответ на вопрос