Арифметика с фиксированной точкой Java с использованием байта

У меня есть некоторые значения, которые принадлежат [-1,1]. Мне не нужна большая точность, но мне понадобится МНОГО этих значений. Теперь я больше разбираюсь в оборудовании, поэтому решение пришло ко мне без особых усилий: использовать арифметику с фиксированной точкой. Я надеюсь сэкономить память, используя 8-битный тип байта Java, который дает точность 2 ^ (-7) = 0,0078125. Есть ли уже доступный способ сделать это и позаботиться о проблемах усечения/переполнения (недо)потока?

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

Спасибо


person capitan    schedule 17.02.2013    source источник
comment
Какие операции вам нужно выполнить, и как вы хотите обрабатывать потери и т.д.?   -  person Jon Skeet    schedule 17.02.2013
comment
В основном вы просто относитесь к числу, как если бы оно было числом с плавающей запятой с двоичной точкой между битом знака и оставшимися битами. Это не дает вам +1,0 (насколько это важно?), но дает -1,0. Сложение/вычитание выполняется прямолинейно, но вам всегда нужно масштабировать после умножения/деления (которое должно выполняться как минимум с 16-битной точностью перед сдвигом).   -  person Hot Licks    schedule 17.02.2013
comment
И имейте в виду, что фактические вычисления будут выполняться с большей точностью — byte всегда расширяется до int в стеке — поэтому ваши локальные переменные также могут быть int.   -  person Hot Licks    schedule 17.02.2013
comment
Также обратите внимание, что в Java есть короткие целые числа, которые составляют 16 бит, но в остальном они воспроизводятся как байты, поэтому вы можете использовать шорты, если байты слишком ограничены.   -  person Hot Licks    schedule 17.02.2013
comment
Так как вы всегда должны выполнять операции в расширенной форме, обнаружение переполнения — это просто проверка того, что незначащие биты более широкого значения совпадают со знаковым битом.   -  person Hot Licks    schedule 17.02.2013
comment
Я делаю все 4 основные арифметические операции с этими значениями. Не знал, что байты были растянуты до 32 бит для работы, поэтому я думаю, что это того не стоит.   -  person capitan    schedule 17.02.2013
comment
Это все еще стоит того с точки зрения хранения (при условии, что подавляющее большинство ваших значений хранятся в массивах байтов или в полях экземпляров байтов). Операции расширения/сужения выполняются довольно быстро, и вы в любом случае можете воспользоваться дополнительной шириной, чтобы помочь с обнаружением переполнения.   -  person Hot Licks    schedule 17.02.2013


Ответы (2)


Есть ли уже доступный способ сделать это и позаботиться о проблемах усечения/переполнения (недо)потока?

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

Это можно сделать... если вы будете осторожны.


Но стоит ли?

Первое, что нужно учитывать, это то, что поле byte или локальная переменная занимает точно такое же пространство, как поле int или float... 32 бита. (Или потенциально больше на 64-битной машине.)

На самом деле вы сэкономите память только в том случае, если байты на самом деле являются членами byte[].

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

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

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


Я был бы склонен реализовать приложение, просто используя float, который автоматически позаботится обо всех проблемах переполнения и потери значимости. Затем запустите приложение на реальных данных, чтобы увидеть, насколько оно быстрое и сколько памяти оно использует:

  • Если оба варианта приемлемы, оставьте их в покое.
  • If memory usage is too great or speed are too slow, THEN look at ways to fix this. If you decide to try the scaled number approach:
    • implement the key computations using float and byte
    • тест, чтобы исправить масштабированный арифметический код, и
    • тщательно сравните обе версии, чтобы оценить различия.

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

person Stephen C    schedule 17.02.2013
comment
Я имею дело с графиками, которые якобы должны хорошо масштабироваться. Для каждого узла графа в идеале потребуется 200-300 значений. Я думал разместить как можно больше узлов, но я думаю, что масштабируемость в конце концов не стоит проблем. Я буду придерживаться поплавка. - person capitan; 17.02.2013
comment
Хороший план. Если масштабируемость (с ограниченным объемом памяти) окажется критически важной в будущем, вы всегда можете пересмотреть реализацию. - person Stephen C; 17.02.2013
comment
Не всегда верно, что поля экземпляра байта на самом деле занимают 32 бита. - person Hot Licks; 17.02.2013
comment
@HotLicks - знаете ли вы примеры, когда это не так? (Давайте исключим Java ME ... потому что это вряд ли будет актуально.) - person Stephen C; 18.02.2013
comment
Я точно знаю, что IBM iSeries Java, около 2001 года, не выделяла 32 бита на байт, потому что я был тем, кто их не выделял. (И, сделав это таким образом, производительность улучшилась примерно на 5% в тестах, заняв первое место в войнах тестов.) - person Hot Licks; 18.02.2013

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

последний байт х = -1; последний байт у = 1;

Помните, что с байтовыми типами данных вы должны быть немного осторожны.

байт b1 = х*у; дает ошибку. Сделайте следующее.

байт b1 = (байт) (x*y);

person nageswara rao    schedule 17.02.2013