Розумієте "ibase" та "obase" у випадку конверсій з bc?


22

Я часто використовую bcутиліту для перетворення шістнадцяткових в десяткові і навпаки. Проте, це завжди біт проб і помилок, як ibaseі obaseпотрібно налаштувати. Наприклад, тут я хочу перетворити шістнадцяткове значення C0 в десяткове:

$ echo "ibase=F;obase=A;C0" | bc
180
$ echo "ibase=F;obase=10;C0" | bc
C0
$ echo "ibase=16;obase=A;C0" | bc
192

Яка тут логіка? obase( Aу моєму третьому прикладі) потрібно знаходитись у тій самій базі, що і значення, яке перетворюється ( C0у моїх прикладах), і ibase( 16у моєму третьому прикладі) має бути в тій базі, куди я перетворююсь?


1
для шістнадцяткових обчислень (введення та виведення у шістнадцятковій) я повинен встановити obase перед ibase!
Пашаліс

Відповіді:


36

Насправді ви хочете сказати:

$ echo "ibase=16; C0" | bc
192

для шістнадцяткових до десяткових і:

$ echo "obase=16; 192" | bc
C0

для десяткової-шестигранної.

Вам не потрібно вводити як ibaseі obaseдля будь-якого перетворення, що включає десяткові числа, оскільки ці параметри за замовчуванням до 10.

Ви дійсно повинні дати як для таких перетворень , як виконавчі-на-шістнадцятковий. У такому випадку мені найлегше зрозуміти речі, якщо ви дасте obaseперше:

$ echo "obase=16; ibase=2; 11000000" | bc
C0

Якщо ви подаєте ibaseперший замість цього, він змінює інтерпретацію наступних obaseпараметрів, так що команда повинна бути:

$ echo "ibase=2; obase=10000; 11000000" | bc
C0

Це тому, що в цьому порядку obaseзначення інтерпретується як двійкове число, тому вам потрібно дати 10000₂ = 16, щоб отримати вихід у шістнадцятковій. Це незграбно.


Тепер давайте розберемося, чому ваші три приклади поводяться так, як вони.

  1. echo "ibase=F;obase=A;C0" | bc

    180

    Це встановлює вхідну базу на 15, а вихідну базу - на 10, оскільки одноцифрове значення інтерпретується у шістнадцятковій формі згідно POSIX . Це вимагає bcсказати вам, що C0₁₅ знаходиться в базі A₁₅ = 10, і це правильно відповідає 180₁₀, хоча це, звичайно, не те питання, яке ви хотіли задати.

  2. echo "ibase=F;obase=10;C0" | bc

    C0

    Це нульове перетворення в базі 15.

    Чому? По-перше, тому що однозначна Fінтерпретація у шістнадцятковій формі, як я вказував у попередньому прикладі. Але тепер, коли ви встановили його на базу 15, таким чином інтерпретується наступне налаштування вихідної бази та 10₁₅ = 15, тому у вас є перетворення нуля з C0₁₅ в C0₁₅.

    Правильно, вихід не в шістнадцятковій формі, як ви припускали, він знаходиться в базі 15!

    Ви можете довести це собі, намагаючись перетворити F0замість C0. Оскільки Fв базі 15 немає цифри, bcзатискає її E0і дає E0як вихід.

  3. echo "ibase=16; obase=A; C0"

    192

    Це єдиний із трьох ваших прикладів, який, ймовірно, має практичне використання.

    По- перше , це змінює вхідну базу на шестнадцяткову , щоб вам більше не потрібно було копатися в специфікації POSIX, щоб зрозуміти, чому Aв цьому випадку інтерпретується як шестнадцятеричний. Єдина проблема з цим полягає в тому, що надмірно встановлювати вихідну базу на A₁₆ = 10, оскільки це її значення за замовчуванням.


7

Налаштування ibaseозначає, що вам потрібно встановити obaseту саму базу. Пояснення ваших прикладів покаже це:

echo "ibase=F;obase=A;C0" | bc

Ви налаштовуєте bcвраховувати вхідні номери, представлені в базі 15, з "ibase = F". "obase = A" встановлює вихідні номери на базі 10, що є типовим.

bc читає C0 як базове 15 число: C = 12. 12 * 15 = 180.


echo "ibase=F;obase=10;C0" | bc

У цьому випадку ви встановлюєте вхід на базу 15, а вихід на 10 - на базу 15, тому вихідна база дорівнює 15. Вхід 0 в базі 15 - вихід C0 в базі 15.


echo "ibase=16;obase=A;C0" | bc

Встановіть вхід на базу 16, вихід на базу 10 (А в базі 16 - 10 в базі 10).

C0, перетворений на базу 10, дорівнює: 12 * 16 = 192


Моє особисте правило - спершу встановити obase, щоб я міг використовувати базу 10. Потім встановити ibase, також використовуючи базу 10.

Зауважте, що у bcних є іронічний виняток: ibase=Aі obase=Aзавжди встановлює вхід і вихід на базу 10. На bcсторінці "man":

Single digit numbers always have the value of the digit 
regardless of the value of ibase.

Така поведінка закріплена в специфікації bc: Від специфікації OpenGroup 2004 рокуbc :

When either ibase or obase is assigned a single digit value from 
the list in 'Lexical Conventions in bc', the value shall be assumed
in hexadecimal. (For example, ibase=A sets to base ten, regardless 
of the current ibase value.) Otherwise, the behavior is undefined 
when digits greater than or equal to the value of ibase appear in
the input.

Ось чому ibase=Fналаштування змінило вашу вхідну базу на базу 15, і чому я рекомендував завжди встановлювати базову, використовуючи базу 10. Не уникайте плутати себе.


@ StéphaneChazelas - у мене є спогад про "ibase = A", який працював на машині SysVr3 в 1989 році. Б'юсь об заклад, що це відходить далі, ніж Single Unix Spec. Я не міг швидко google до більш ранній ref.
Брюс Едігер

Я думаю, що це тому, що існує більше посилань на старі специфікації, оскільки вони існують довше. Такі ж речі трапляються і для апаш / mysql / bugzilla ... документації, де Google надає вам документ для старих версій спочатку замість останньої.
Стефан Шазелас

5

Усі числа інтерпретуються GNU bc як поточна база вводу, яка діє для висловлювання, про яке відображається число. Коли ви використовуєте цифру поза поточним входом, інтерпретуйте їх як найбільшу цифру, наявну в базі (9 у десятковій частині), коли частина багатоцифрового числа або як їх нормальні значення при використанні як одноцифрове число ( A== 10 у десятковій кількості).

З посібника GNU bc :

Одноцифрові числа завжди мають значення цифри незалежно від значення ibase . (тобто A = 10.) Для багатоцифрових чисел зміняйтеbc всі вхідні цифри, більші або рівні ibase, на значення ibase -1. Завдяки цьому число FFFзавжди є найбільшим тризначним числом вхідної бази.

Однак слід пам’ятати, що стандарт POSIX визначає цю поведінку лише для призначення ibaseта obase, а не в будь-якому іншому контексті.

З специфікації SUS на bc :

Коли небудь IBase або obase присвоюється один значне значення зі списку в лексичних конвенцій в БЛ, значення повинно бути прийнято в шістнадцятковому форматі. (Наприклад, ibase = Встановлює базове десять, незалежно від поточного значення ibase .) В іншому випадку поведінка не визначена, коли на вході відображаються цифри, що перевищують або дорівнюють значенню ibase . Як ibase, так і obaba мають початкові значення 10.

Ключовим фактором, якого вам не вистачає, є те, що F насправді не шістнадцять, а насправді п’ятнадцять, тож, коли ви встановлюєте ibase = F, ви встановлюєте базову вхід до п'ятнадцяти.

Тому, щоб стерпний встановити IBase в шістнадцятковий з невідомого держави, то , отже , необхідно використовувати два заяву: ibase=A; ibase=16. Однак на початку програми ви можете розраховувати на те, що вона буде десятковою та просто використовувати ibase=16.


+1: Милий трюк із ibase=A; ibase=16.
Воррен Янг

Це SUSv3, а не SUSv6. SUSv4 знаходиться за адресою pubs.opengroup.org/onlinepubs/9699919799/utilities/bc.html
Stéphane Chazelas

Я завжди думав, що версії 6 та 7 у заголовках - це версія. Я ніколи не бачив нічого іншого - що таке питання №1-5?
Випадково832

@ Random832: SUS і POSIX - це не одне і те ж .
Воррен Янг

@WarrenYoung Чи SUS не містить POSIX? У цьому абзаці немає тегу розширення, і в документі написано такі речі, як "частина цього обсягу POSIX.1-2008".
Випадково832

0

Завжди рекомендується встановлювати ibaseта obaseвикористовувати одноцифрове число, а не таке число, як 16, наприклад , відповідно до bcсторінки людини,

Одноцифрові числа завжди мають значення цифри незалежно від значення ibase.

Це означає, що значення A,B,...,Fзавжди мають 10,11,...,15відповідно, незалежно від значення ibase. Ви також F+1можете вказати номер 16. Наприклад, вам краще написати

echo "ibase=F+1; obase=A; C0" | bc

замість написання, echo "ibase=16; obase=A; C0" | bcщоб вказати, що вхідна база є, 16а вихідна база є 10. Або, наприклад, якщо ви хочете, щоб і те, ibaseі obaseбуло 16, вам краще скористатися

ibase=F+1; obase=F+1

замість використання ibase=16; obase=10. Аналогічно, якщо ви збираєтеся вводити свої номери в базі 14 та виводити їх у базі 16, використовуйте

ibase=E; obase=F+1

Хоча форми для ванни мають однакові результати, перші менш схильні до помилок, тоді як другі можуть призвести до більшої плутанини та помилок.

Різниця між цими двома формами особливо стає більш очевидною, коли ви перебуваєте в середовищі виконання bcабо ви збираєтеся записати свої обчислення у файл, а потім передати цей файл bcяк аргумент. У таких ситуаціях, можливо, доведеться змінити значення ibaseі obaseкілька разів, а використання останньої форми може призвести до серйозної плутанини та помилок. (досвід цього)

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.