Преобразовать целочисленное значение в число с плавающей запятой с размером шага в зависимости от диапазона - PullRequest
0 голосов
/ 29 октября 2018

У меня есть ползунок, который я использую для изменения параметра (y), который может иметь широкий диапазон значений.Положение ползунка задается как целое число (x).

Мой параметр содержит энергию источника и может иметь значения от 0,1 нДж до 10 Дж. Для целей применения Iразмер шага параметра должен быть:

  • 0,1 нДж в [0,1 нДж - 1,0 мкДж]
  • 0,1 мкДж в [1,0 мкДж - 1,0 мДж]
  • 0,1 мДж в [1,0 мДж - 1,0 Дж]
  • 0,1 Дж в [1,0 Дж - 10,0 Дж]

Я пытаюсь преобразовать эти значения (x => y) с помощьюоперации целочисленного деления (//) и остатка (%), но я сталкиваюсь с проблемами, например, при переходе из одного поддиапазона в другой.

x = 9999 дает y =999,9 нДж, что и должно, но тогда x = 10000 дает y = 0,0 мкДж, что в системе равно 0 и намного ниже, чем 999,9 нДж.Следующий шаг (x = 10001) дает y = 0,1 мкДж, что также ниже, чем 999,9 нДж.

В идеале шаги y должны составлять 999,9 нДж - 1,0 мкДж - 1,1 мкДж.

ЭтоMWE использует обнаружение клавиш для считывания ввода клавиш без необходимости нажатия клавиши ENTER.

import math as m
import sys, termios, tty, os, time

prefixes =   {-18:'a', -15:'f', -12:'p', -9:'n',    # Prefixes for displaying the value
        -6:'\u03bc', -3:'m', #-2:'c', -1:'d',
        +0:'', #+1:'da', +2:'h', 
        +3:'k', +6:'M', +9:'G', +12:'T', +15:'P', +18:'E'}

def getch():                    # Get character from keyboard without waiting for enter
    fd = sys.stdin.fileno()
    old_settings = termios.tcgetattr(fd)
    try:
        tty.setraw(sys.stdin.fileno())
        ch = sys.stdin.read(1)
    finally:
        termios.tcsetattr(fd, termios.TCSADRAIN, old_settings)
    return ch

def calcy():                        # Convert from x integer to y value for display
    print("x: " + repr(x))
    exp2 = 3*((x/resolution) // 1e+3) + exp0    # integer division
    yp2 = round((x/resolution)%(1e+3), digits)  # remainder
    y2 = round(yp2 * m.pow(10, exp2), int(digits-exp2))
    print("y: " + repr(y2) + "   equal to " + repr(yp2) + str(prefixes[exp2]) + "J\n")

button_delay = 0.1

y = float(input("Give starting value:"))    # Choose a value to start from

exp0 = -9                                     # Exponent of minimum range [nJ]
digits = 1                                  # Number of decimals to be used
resolution = m.pow(10, 1)                   # The number of points for a change of size 1

exp = 0                                     # Exponent of y
yp = y                                      # Short number of y
while yp < 1/resolution:                    # While the number is not in the prefixed unit
    yp = yp*1e+03                           # Multiply yp by 1000 (10³)
    exp -= 3                                # Exponent increases by 3

yp = round(y * m.pow(10, -exp), digits)     # The display value 
x = int((yp + (exp - exp0)/3 * 1e+3) * resolution)   # Integer value representing the silder value

calcy()                                     # Calculate y from x integer

while True:
    char = getch()            # Get pressed key

    if char == 'q':           # If it was q, quit
        exit(0)
    elif char == '+':         # If it was +, increase x by one and
        x += 1                # recalculate y
        calcy()
        time.sleep(button_delay)
    elif char == '-':        # If it was -, decrease x by one and 
        x -= 1               # recalculate y
        calcy()
        time.sleep(button_delay)
    else:
        print(char)
        time.sleep(button_delay)

Если вы хотите попробовать эту программу, я рекомендую указать 500e-9 в качестве начального значения инажимая - 6 раз, чтобы получить y = 999,9 нДж, потому что здесь все идет не так.

Я понимаю, что логично для x = 10001 преобразовать в 0,1 мкДж с помощью алгоритма, который я использую, но я нене знаю, как это решить.Если бы вы могли изменить значение только с помощью кнопок + и -, можно было бы перейти непосредственно с 9999 на 10011, что логически дало бы y = 1,1 мкДж, но как бы я тогда справился с тем фактом, что фактический слайдер можно перетаскиватьс помощью мыши?

Пожалуйста, дайте мне какие-нибудь идеи, как решить эту проблему.

Ответы [ 2 ]

0 голосов
/ 31 октября 2018

Благодаря комментариям и предложениям @ Davis-Herring, я думаю, что решил это.Теперь функцию можно настроить для разных разрешений (размеров шагов) и начальных показателей (exp0).

def calcy(x):
    if x < (1000*resolution - 1):        # The number of values from the start to the first prefix change
        exp = exp0
        yp = round((x + 1)/resolution, digits) # Round to account for numerical discrepancies
    else:
        n = round((1000 - 1) * resolution) # The number of values in all other ranges
        z = round(x - (1000 * resolution - 1)) # Subtract the number of values in the first range
        r = z // n + 1          # The number of passed ranges
        yp = round((z % n)/resolution + 1, digits)
        exp = exp0 + 3 * r
    return yp * 10**exp

При resolution = 10 и digits = 1 каждый шаг в первом диапазоне равен 0,1 нДж, а затем 0,1мкДж, 0,1 мДж ......

0 голосов
/ 29 октября 2018

У вас есть 9999 значений в каждом полуоткрытом интервале и 90 в последнем, закрытом интервале, потому что (например) 10000 (0,1 нДж) = 1 мкДж. Это облегчает преобразование:

def val(x):   # 0<=x<30,087
  r,x=divmod(x,9999)
  return (x+1)*1000**(r-3)/10

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

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