Понимание дополнения Two к float (метка датчика Texas Instruments)

Я нашел пример кода для извлечения температуры из тега датчика Texas Instruments на github: https://github.com/msaunby/ble-sensor-pi/blob/master/sensortag/sensor_calcs.py

Я не понимаю, что делает следующий код:

tosigned = lambda n: float(n-0x10000) if n>0x7fff else float(n)

Как я прочитал приведенный выше фрагмент кода:

if n>0x7fff: n = float(n-0x10000)
else n = float(n)

В основном происходит то, что значение дополнения two (n) преобразуется в число с плавающей запятой. Почему это должно происходить только тогда, когда значение n больше 0x7fff? Если значение равно 0x7fff или меньше, мы просто конвертируем i в число с плавающей запятой. Почему? Я этого не понимаю.

Пример кода от Texas Instruments можно найти здесь: http://processors.wiki.ti.com/index.php/SensorTag_User_Guide#SensorTag_Android_Development

Почему возвращаемое значение делится на 128,0 в этой функции в примере кода TI?

private double extractAmbientTemperature(BluetoothGattCharacteristic c) {
    int offset = 2;
    return shortUnsignedAtOffset(c, offset) / 128.0;
}

Я задавал этот вопрос разработчику, но ответа не получил.


person MeesterPatat    schedule 29.01.2015    source источник
comment
Вы смотрели на разницу между, например. float(0x8fff) и float(0x8fff-0x10000)? Подсказка в имени tosigned!   -  person jonrsharpe    schedule 29.01.2015
comment
Да, я это понимаю, но почему он будет преобразован в подписанный только в том случае, если значение больше 0x7fff?   -  person MeesterPatat    schedule 29.01.2015


Ответы (2)


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

Положительные значения 16-битного целого числа со знаком будут храниться в диапазоне 0x0001-0x7fff, а его отрицательные значения — в диапазоне 0x8000-0xffff. Если это значение было прочитано каким-то образом, без проверки бита знака (возможно, как целое число без знака, или часть более длинного целого числа, или собрано из двух байтов), то нам нужно восстановить знак.

Как? Что ж, если значение больше 0x7fff, мы знаем, что оно должно быть отрицательным, а отрицательные значения сохраняются как дополнение до двух. Поэтому мы просто вычитаем из него 0x10000 и получаем отрицательное значение.

person Kevin S    schedule 29.01.2015
comment
Разве это не 0x0001-0x7fff для положительных целых чисел? - person MeesterPatat; 30.01.2015
comment
@MeesterPatat Похоже, у меня пукнул мозг, и я изначально написал 7999 вместо 7fff. Стив исправил это. - person Kevin S; 30.01.2015

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

Вы можете поиграть с этим самостоятельно, используя интерпретатор Python:

tosigned = lambda n: float(n-0x10000) if n>0x7fff else float(n)
print(tosigned(0x3fff))

против:

unsigned = lambda n: float(n)

Проверьте это, чтобы узнать больше:

http://www.swarthmore.edu/NatSci/echeeve1/Ref/BinaryMath/NumSys.html

person duims    schedule 29.01.2015
comment
Я понимаю, о чем вы говорите, поэтому шестнадцатеричное значение 0x7fff и меньше никогда не может быть отрицательным, если оно состоит из двух байтов, потому что старший бит не может быть равен 1 (7 в двоичном коде равно 0111). Поскольку 0x7fff и меньше не являются отрицательными числами, нам не нужно их преобразовывать? Я правильно понимаю? - person MeesterPatat; 30.01.2015