преобразование с плавающей точкой в ​​32-битную фиксированную точку в Java - PullRequest
7 голосов
/ 04 августа 2010

Мне нужно преобразовать плавающую точку в 32-битную фиксированную точку в Java.

Не в состоянии понять, что такое 32-битная фиксированная точка?

Может ли тело помочь с алгоритмом?

Ответы [ 4 ]

20 голосов
/ 04 августа 2010

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

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

32-разрядное число с фиксированной запятой будет сохранено в 32-разрядном типе, таком как int.

Обычно каждый бит в целочисленном типе (в данном случае без знака) представляет целое значение 2 ^ n следующим образом:

 1    0    1    1    0    0    1    0       = 2^7 + 2^5 + 2^4 + 2^1 = 178
2^7  2^6  2^5  2^4  2^3  2^2  2^1  2^0

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

 1    0    1    1    0    0    1    0       = 2^3 + 2^1 + 2^0 + 2^-3 = 11.125
2^3  2^2  2^1  2^0  2^-1 2^-2 2^-3 2^-4

Номер с фиксированной точкой в ​​приведенном выше примере называется номером с фиксированной точкой 4,4, поскольку в целочисленной части 4 бита, а в дробной части 4 бита. В 32-битном типе значение с фиксированной точкой обычно будет в формате 16.16, но также может быть 24,8, 28,4 или любой другой комбинацией.

Преобразование из значения с плавающей запятой в значение с фиксированной запятой включает в себя следующие шаги:

  1. Умножить число с плавающей запятой на 2 ^ (количество дробных бит для типа), например. 2 ^ 8 для 24,8
  2. Округлите результат (просто добавьте 0,5), если необходимо, и напишите его (или приведите к целочисленному типу), оставив целочисленное значение.
  3. Присвойте это значение типу с фиксированной запятой.

Очевидно, что вы можете потерять некоторую точность в дробной части числа. Если важна точность дробной части, это может отражать выбор формата с фиксированной запятой - например, используйте 16,16 или 8,24 вместо 24,8.

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

Если бы мой Java был сильнее, я бы попробовал какой-то код, но я обычно пишу такие вещи на C, поэтому я не буду пытаться использовать Java-версию. Кроме того, версия stacker выглядит хорошо для меня, за небольшим исключением, что она не предлагает возможности округления. Он даже показывает, как выполнить умножение (сдвиг важен!)

4 голосов
/ 04 августа 2010

Очень простой пример для преобразования в фиксированную точку, он показывает, как преобразовать и умножить PI на 2. Полученный результат конвертируется обратно в двойное число, чтобы продемонстрировать, что мантисса не была потеряна во время вычисления с целыми числами.

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

public class Fix {

    public static final int FIXED_POINT = 16;
    public static final int ONE = 1 << FIXED_POINT;

    public static int mul(int a, int b) {
        return (int) ((long) a * (long) b >> FIXED_POINT);
    }

    public static int toFix( double val ) {
        return (int) (val * ONE);
    }

    public static int intVal( int fix ) {
        return fix >> FIXED_POINT;
    }

    public static double doubleVal( int fix ) {
        return ((double) fix) / ONE;
    }

    public static void main(String[] args) {
        int f1 = toFix( Math.PI );
        int f2 = toFix( 2 );

        int result = mul( f1, f2 );
        System.out.println( "f1:" + f1 + "," + intVal( f1 ) );
        System.out.println( "f2:" + f2 + "," + intVal( f2 ) );
        System.out.println( "r:" + result +"," + intVal( result));
        System.out.println( "double: " + doubleVal( result ));

    }
}

OUTPUT

f1:205887,3
f2:131072,2
r:411774,6
double: 6.283172607421875
2 голосов
/ 04 августа 2010

Тип с фиксированной запятой - это тип с фиксированным числом десятичных / двоичных разрядов после радикальной точки. Или, в общем, тип, который может хранить кратные 1 / N для некоторого положительного целого числа N.

Внутренне числа с фиксированной запятой сохраняются как значение, умноженное на коэффициент масштабирования. Например, 123,45 с коэффициентом масштабирования 100 сохраняется, как если бы это было целое число 12345.

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

1 голос
/ 04 августа 2010

Определение 32-битной фиксированной точки может отличаться. Общая идея фиксированной точки состоит в том, что у вас есть некоторое фиксированное количество бит до и другое фиксированное количество бит после десятичной точки (или двоичной точки). Для 32-битного, наиболее распространенное разделение, вероятно, четное (16 до, 16 после), но в зависимости от цели это не гарантируется.

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

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...