又來到了明天還要上班的週日
我難過(´・_・`)
算了反正下禮拜也還有週末,不怕不怕
今天要來的介紹是進制轉換
由於我的公司是硬體公司,而我工作內容基本都是撰寫控制硬體設備的輔助工具
因此時常要寫一些跟資訊交換有關的程式
而在這些程式中,通訊的方式與協定就顯得無比重要
又因為我們公司的設備溝通都以16進制(Hex)為主
因此才又回顧那些在數位邏輯課中所教到的進制轉換問題(´・з・)
今天的程式很少很簡單,但是背後都牽涉到那些當年早就還給老師的數位邏輯的問題
我在這邊懶得講理論,網路上隨便打都有,建議不會的同學可以先爬文喔~
當然真的搞不懂也歡迎發問XD
那今天的介紹開始
在開始之前,請先上這個網站
https://cryptii.com/pipes/integer-encoder
這是一個我目前覺得最好用的位數計算器(`・ω・´)
而今天我APP計算出來的結果基本上也是用這個下去比對做解答
那麼請你按照我這樣設定
完成後可以自己試著輸入一些16進制的數值
了解操作後,接著正式開始我們今天的介紹
成品:
今天預計要達成的目標:
1.輸入16進制
2.算出10進制值
3.算出8進制值
4.算出2進制值
5.算出帶負號的值
最後,Github在此
https://github.com/thumbb13555/ConvertValueExample
進制問題其實說容易
因為其實在Java中,他老早就幫你寫好了
你只要懂得運用即可
在型態轉換的工具中,有一個轉換工具是String轉int的
如下:
int i = Integer.parseInt("99887766");
"99887766"雖然是一串字串格式,但是用這個工具就可以轉為int格式
此外還有很多,像是轉double、char或其他轉為String等等都很常見
關於這方面可參考
https://hsinichi.pixnet.net/blog/post/5317015
他寫得很詳細。
那重點就在這裡
像我在收到這些資訊時,因為只有String格式可以自由拆解資料
因此通常我拿到資料後需要拆解的我都會先轉String格式
但問題來了,如果你今天輸入了16進制的A~F
你就會出現以下問題
java.lang.NumberFormatException: For input string: "a2"
at java.lang.Integer.parseInt(Integer.java:615)
at java.lang.Integer.parseInt(Integer.java:650)
at com.example.convertvalueexample.MainActivity.convert(MainActivity.java:32)
at com.example.convertvalueexample.MainActivity.lambda$onCreate$0$MainActivity(MainActivity.java:26)
at com.example.convertvalueexample.-$$Lambda$MainActivity$nuSFrx0u7jA69cc4gyoNVvsrmPM.onClick(Unknown Source:2)
at android.view.View.performClick(View.java:7339)
at android.widget.TextView.performClick(TextView.java:14222)
at android.view.View.performClickInternal(View.java:7305)
at android.view.View.access$3200(View.java:846)
at android.view.View$PerformClick.run(View.java:27787)
at android.os.Handler.handleCallback(Handler.java:873)
at android.os.Handler.dispatchMessage(Handler.java:99)
at android.os.Looper.loop(Looper.java:214)
at android.app.ActivityThread.main(ActivityThread.java:7078)
at java.lang.reflect.Method.invoke(Native Method)
at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:494)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:964)
這個摁提的意思就是他預設轉型為10進制,但是你輸入了a2
因此拋出NumberFormatException
這時候很簡單,只要把程式改成
int i = Integer.parseInt("22FA",16);
就可以解決問題囉
(`・ω・´)
而你接到的數字也將會是10進制
再來是轉出問題
轉出也很簡單
只要
Integer.toHexString(123);
就可以囉!
其他的就只要這樣
Integer.toBinaryString(123);
Integer.toOctalString(123);
一樣可以得到相同的效果
也就是說,其實程式裡面
只要有上述的轉入及轉出,就可大體完成整個功能了
結果大概像這樣
然後...
恩?好像哪裡怪怪的
這時用我前面的連結來驗證一下
答案其實就是,我一開始請你選擇的是16位元簽署 (16-bit signed Integer)
因此如果你選擇16-bit unsigned Integer
得到的就是剛才的結果一樣
但問題是...很多時候我們要的就是那些負號RRRRR(ノ`□´)ノ⌒┻━┻
這時候我們第一目標先處理好轉10進制的問題
在我範例程式中的第32行
long input = (short)Integer.parseInt(edInput.getText().toString(),16);
就結論而言
只要加入這行就可以搞定16進制的部分了
至於原理在這
https://stackoverflow.com/questions/15202958/16-bit-hex-string-to-signed-int-in-java
其中的這
在下英文不好就不幫忙翻譯了~
簡單來說就是因為強制轉型短整數的緣故,而忽略第16位元
取而代之使用地15位元作為符號位元(判定正負)
因此才能有效顯示
再來就是八進制與二進制的問題啦
關於八進制轉負數的問題,可能因為八進制相較二進與十六進算比較少用
因此網路上關於如何取負數的資料幾乎沒有
這時候你就要想想你當年的數位邏輯老師的臉龐了
敢情大概也想不起來吧(・ω・`)………..
其實這時候就是"補數"的概念要出場啦(`・ω・´)b
關於這部分可參考
https://www.javaworld.com.tw/jute/post/view?bid=29&id=246959
其中你只要在你的數值前面加入“~”就好
詳情Github中35行
講講2進位的補數
如果你今天數值是0100 1101
那取補數就會變1011 0010
這時候補數還沒完,你還要再+1才有用
因此就變成1011 0011
最後手動加上負號就完成
因此最後出來的程式長這樣
edBinary.setText("-"+Long.toBinaryString(~input+1));
Long是長整數,改為int也可以
至於八進位的原理也是一樣,一樣的程式套用就好
最後結果
最後我們在回頭看程式
public class MainActivity extends AppCompatActivity {
String TAG = MainActivity.class.getSimpleName()+"m";
Button btConvert;
EditText edInput,edBinary,edOctal,edDecimal;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
btConvert = findViewById(R.id.button);
edInput = findViewById(R.id.input);
edBinary = findViewById(R.id.binary);
edOctal = findViewById(R.id.octal);
edDecimal = findViewById(R.id.decimal);
btConvert.setOnClickListener((v)->{convert();});
}
private void convert(){
if (edInput.getText().toString().length()>0){
int input = (short)Integer.parseInt(edInput.getText().toString(),16);
edDecimal.setText(String.valueOf(input));
if(input<0){
edBinary.setText("-"+(Long.toBinaryString(~input+1)));
edOctal.setText("-"+Long.toOctalString(~input+1));
}else{
edBinary.setText(Long.toBinaryString(input));
edOctal.setText(Long.toOctalString(input));
}
if (Long.toBinaryString(input).length()<8){
edBinary.setText(String.format("%08d",Integer.parseInt(Long.toBinaryString(input))));
}
}
}
}
醬子好像多少有看懂了一些嗎XD
喔對了補充
因為本身在補數判定只能判定4個字元
因此我在輸入筐內有設定這個
android:maxLength="4"
限制最大輸入為4這樣,特請多多留意囉
還有最後藍字的部分是針對二進位如果少於8格字元就自動補0的方法
參考看看吧!
留言列表