كيف تحسب النقطة العائمة في راديكس بخلاف 10؟
-
06-09-2019 - |
سؤال
بالنظر إلى مقال ويكيبيديا نقطة radix., ، كيف يمكن للمرء حساب المكافئ الثنائي 10.1 أو ما يعادل عشرية 17.17؟ بالنسبة إلى السابق، ما هو ما يعادل الثنائي العاشر؟ لهذا الأخير، تمثيل عرافة 17/100؟
أبحث عن خوارزمية أكثر من الحلول لتلك الأمثلة فقط.
المحلول
لتحويل عشري 10.1 إلى ثنائي، افصل الأجزاء العددية والكسرية وتحويل كل منهما بشكل منفصل.
لتحويل الجزء الصحيح، استخدم تقسيم عدد صحيح متكرر بنسبة 2، ثم اكتب الباقي بترتيب عكسي:
10/2 = 5 باقي 0
5/2 = 2 الباقي 1
2/2 = 1 الباقي 0
1/2 = 0 ما تبقى 1
الجواب: 1010.
لتحويل الجزء الكسري، استخدم الضرب المتكرر بنسبة 2، وطرح الجزء الأمثل في كل خطوة. تمثل الأجزاء الصحيحة، حسب جيل، رقمك الثنائي:
0.1 * 2 = 0.2
0.2 * 2 = 0.4
0.4 * 2 = 0.8
0.8 * 2 = 1.6
0.6 * 2 = 1.2
0.2 * 2 = 0.4
0.4 * 2 = 0.8
... (دورة تكرر إلى الأبد)
لذلك Decimal 0.1 ثنائي 0.000110011001100 ...
(للحصول على شرح أكثر تفصيلا، انظر الروتين dec2bin_i () و dec2bin_f () في مقالتي http://www.exploringbinary.com/base-conversion-in-php-using-bcmath/ .)
للحصول على السداسي عشري، استخدم نفس الإجراء، باستثناء مقسمي / مضاعف من 16 بدلا من 2. يجب تحويل الأجزاء العبقية والأجزاء العددية أكبر من 9 إلى أرقام Hex مباشرة: 10 يصبح A، 11 يصبح ب، ...، 15 يصبح F وبعد
نصائح أخرى
رقم إنهاء (رقم يمكن تمثيله بعدد محدود من الأرقام)1 في قاعدة ب1, ، قد ينتهي كونه رقم غير مهم في قاعدة مختلفة ب2. وبعد على العكس، عدد عدم الإنهاء في قاعدة واحدة ب1 قد تتحول إلى رقم إنهاء في قاعدة ب2.
الرقم 0.1.10 عند تحويلها إلى ثنائي رقم غير مهم، كما هو 0.1710 عند تحويلها إلى رقم سداسي عشري. ولكن ينهي رقم 0.13 في Base 3، عند تحويلها إلى Base 10 هو عدم الإنهاء، رقم التكرار 0. (3)10 (يدل على أن الرقم 3 يكرر). وبالمثل، تحويل 0.110 إلى ثنائي و 0.1710 إلى سداسي عشري، ينتهي المرء بأرقام عدم الإنهاء المتكررة 0.0 (0011)2 و 0.2 (B851E)16
لهذا السبب، عند تحويل هذا الرقم من قاعدة واحدة إلى أخرى، قد تجد نفسك في الاضطرار إلى تقريب الرقم بدلا من وجود تمثيل دقيق تماما.
الخوارزمية بسيطة للغاية، ولكن في الممارسة العملية يمكنك القيام بالكثير من التعديلات مع طاولات البحث والسجلات لتسريعها. ولكن بالنسبة للخوارزمية الأساسية، قد تجرب شيئا مثل هذا:
shift=0;
while v>=base, v=v/base, shift=shift+1;
Next digit:
if v<1.0 && shift==0, output the decimal point
else
D=floor(v)
output D
v=v-D
v=v*base
shift = shift-1
if (v==0) exit;
goto Next Digit
قد تقوم أيضا بوضع اختبار في هناك لإيقاف الطباعة بعد N أرقام لعشرات العشرات الأطول المتكررة.
"المكافئ الثنائي" لعشر واحد هو نصف واحد، أي بدلا من 1/10 ^ 1، إنه 1/2 ^ 1.
يمثل كل رقم قوة اثنين. الأرقام وراء نقطة radix هي نفسها، من أنها تمثل فقط 1 على قوة اثنين:
8 4 2 1 . 1/2 1/4 1/8 1/16
لذلك لمدة 10.1، من الواضح أنك تحتاج إلى "8" و "2" لجعل الجزء 10. 1/2 (0.5) أكثر من اللازم، 1/4 (0.25) هو أكثر من اللازم، 1/8 (0.125) أكثر من اللازم. نحتاج إلى 1/16 (0.0625)، والتي سوف تترك لنا مع 0.0375. 1/32 هو 0.03125، لذلك يمكننا أن نأخذ ذلك أيضا. حتى الآن لدينا:
8 4 2 1 . 1/2 1/4 1/8 1/16 1/32
1 0 1 0 0 0 0 1 1
مع خطأ 0.00625. 1/64 (0.015625) و 1/128 (0.0078125) كلاهما أكثر من اللازم، 1/256 (0.00390625) سيعمل:
8 4 2 1 . 1/2 1/4 1/8 1/16 1/32 1/64 1/128 1/256
1 0 1 0 0 0 0 1 1 0 0 1
مع خطأ 0.00234375.
لا يمكن التعبير عن .1 بالضبط في ثنائي (لا يمكن التعبير عن 1/3 تماما بالضبط). اعتمادا على المكان الذي تضع فيه باديكس، يجب أن تتوقف في النهاية أن تتوقف، وربما جولة، وقبول الخطأ.
قبل أن أكون في ضوء ذلك في ضوء مكتبة GMP الخاصة بي، إليك حيث حصلت على محاولة جعل كود PHP Rick Rican's PHP عام لأي قاعدة من 2 إلى 36.
Function dec2base_f(ByVal ddecimal As Double, ByVal nBase As Long, ByVal dscale As Long) As String
Const BASES = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ" 'up to base 36
Dim digitCount As Long
Dim wholeNumber As Double
Dim digit As String * 1
digitCount = 0
dscale = max(dscale, Len(CStr(ddecimal)) - Len("0."))
Dim baseary_f As String
baseary_f = "0."
Do While ddecimal > 0 And digitCount < dscale
ddecimal = ddecimal * nBase
digit = Mid$(BASES, Fix(ddecimal) + 1)
baseary_f = baseary_f & digit '"1"
ddecimal = ddecimal - Fix(ddecimal)
digitCount = digitCount + 1
Loop
dec2base_f = baseary_f
End Function
Function base2dec_f(ByVal baseary_f As String, nBase As Double) As Double
Const BASES As String = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"
Dim decimal_f As Double
Dim i As Long
Dim c As Long
For i = Len(baseary_f) To Len("0.") + 1 Step -1
c = InStr(BASES, Mid$(baseary_f, i, 1)) - 1
decimal_f = decimal_f + c
decimal_f = decimal_f / nBase
Next
base2dec_f = decimal_f
End Function
Debug.Print base2dec_f(dec2base_f(0.09, 2, 200), 2) --> 0.09
Debug.Print base2dec_f(dec2base_f(0.09, 8, 200), 8) --> 0.09
Debug.Print base2dec_f(dec2base_f(0.09, 16, 200), 16) --> 0.09