Что нового

[Осваивающий, Продвинутый] Конвертация чисел в разные системы счисления и обратно

kaster

Мой Аватар, он лучший самый
Команда форума
Глобальный модератор
Сообщения
4,020
Репутация
626
Построить две функции для конвертации чисел в другую систему счисления и обратно следующего вида
Код:
; Название функции...........: DecToN($decnum, $base)
; Описание функции ..........: Конвертация числа в заданную систему счисления
; Входные параметры..........: $decnum - десятичное целое число
; ...........................: $base - основание системы счисления (не больше 10)
; Выходные параметры.........: Строка вида  'xxnyyyyy', где
; ...........................: xx - основание системы счисления (тоже что и  $base)
; ...........................: n - символ разделяющий основание системы счисления и представление числа
; ...........................: yyyy - представление числа в системе счисления с основанием $base


; Название функции...........: NToDec($nnum)
; Описание функции ..........: Конвертация числа в десятичную систему счисления
; Входные параметры..........: $nnum - число-строка в заданной системе счисления вида 'xxnyyyy'
; Выходные параметры.........: Число в десятичном представлении

Например, число 18118 имеет следующие представления в различных системах счисления (с учетом формата в условии задачи)
Код:
+-----------+-----------------------+
| Основание | Число                 |
+-----------+-----------------------+
| 2         | '2n100011011000110'   |
| 3         | '3n220212001'         |
| 4         | '4n10123012'          |
| 5         | '5n1034433'           |
| 6         | '6n215514'            |
| 7         | '7n103552'            |
| 8         | '8n43306'             |
| 9         | '9n26761'             |
+-----------+-----------------------+
Поэтому DecToN(18118, 6), к примеру, должно давать '6n215514', а NToDec('4n10123012') должно давать 18118.

Использование каких-либо сторонних библиотек запрещено. Код заключайте в тэг спойлера.

PS: Задача ориентировочно расчитана на осваивающих и продвинутых, но при желании и возможности новички так же могут присоединиться к решению
 

Zaramot

I ♥ AutoIt
Сообщения
1,160
Репутация
660
AZJIO,
Там же пишут [Осваивающий, Продвинутый] , а не Гуру :D
 

AZJIO

Меценат
Меценат
Сообщения
2,874
Репутация
1,194
Zaramot
Я думал что я продвинутый. А то я ещё хотел уже выложить вариант до шестнадцатеричной системы.
 

C2H5OH

AutoIT Гуру
Сообщения
1,473
Репутация
333
А я в AutoIt не Гуру. Мне можно. ;D

Код:
$x = 18118
$N = 6

$y = DecToN($x,$N)

ConsoleWrite("y = " & $y & @CR)

$z = NToDec($y)

ConsoleWrite("z = " & $z & @CR)


Func DecToN($decnum, $base)
	Local $res_str = ""
	If $base = 0 Then Return ""
	If $base = 1 Then					;  А вы не знали что существуед единичная система счисления??
		For $i = 1 to $decnum			;
			$res_str &= "1"				;
		Next							;
		$res_str = "1n" & $res_str		;
		Return $res_str					;
	EndIf								;
	While $decnum > 0
		$rest = Mod($decnum, $base)
		If $rest > 9 Then								; сразу как-то получилось и с основаниями больше 10
			$res_str = Chr(55 + $rest) & $res_str		;
		Else											; ну разрыв идёт в ASCII
			$res_str = Chr(48 + $rest) & $res_str		; Chr(48) == "0", Chr(57) == "9"
		EndIf											; Chr(65) == "A", ...
		$decnum = Floor($decnum/$base)
	WEnd
	If $res_str = "" Then $res_str = "0"
	$res_str = String($base) & "n" & $res_str
	Return $res_str
EndFunc

Func NToDec($nnum)
	$narray = StringSplit($nnum, "n")
	if @error Then Return 0
	Local $nbase = Int($narray[1])
	Local $nn = StringLen($narray[2])
	If $nbase = 1 Then Return $nn
	$nnumarray = StringToASCIIArray($narray[2],0, $nn,1)
	Local $exitnum = 0
	For $i = 0 To $nn-1
		$exitnum *= $nbase
		$exitnum += $nnumarray[$i]
		If $nnumarray[$i] > 60 Then
			If ($nnumarray[$i]-55) >= $nbase Then Return 0
			$exitnum -= 55
		Else
			If ($nnumarray[$i]-48) >= $nbase Then Return 0
			$exitnum -= 48
		EndIf
	Next
	Return $exitnum
EndFunc
 
Автор
kaster

kaster

Мой Аватар, он лучший самый
Команда форума
Глобальный модератор
Сообщения
4,020
Репутация
626
C2H5OH [?]
А вы не знали что существуед единичная система счисления?
знали. но она интереса не представляет, только если ты не ребенок дошкольного возраста, который учиться считать на палочках :smile:
у тебя ошибка в обратной функции. она возвращает 0
 

C2H5OH

AutoIT Гуру
Сообщения
1,473
Репутация
333
у тебя ошибка в обратной функции. она возвращает 0
Это я на ходу вдруг придумал добавить проверку на то что в числе попалась цифра больше чем основание системы счисления. :-[
Немного не туда поставил эту проверку... Уже исправил. :smile:
 

xCite

Новичок
Сообщения
9
Репутация
0
Наконец-то победил))))
Код:
$x1 = DecToN(200, 6)
$x2 = NToDec("8n500")
MsgBox (0, "", $x1)
MsgBox (0, "", $x2)

Func DecToN($DecNum, $Base)
   Local $Output = ""
   $Del = $DecNum
   While $Del > 0
	  $Ost = Mod($Del, $Base)
	  $Output = Chr(48 + $Ost) & $Output
	  $Del = Int($Del / $Base)
   WEnd
   $Output = $Base & "n" & $Output
   Return $Output
EndFunc

Func NToDec($Input)
   Local $Output = 0
   $BaseAndNum = StringSplit($Input, "n")
   $Base = $BaseAndNum[1]
   $BaseNum = $BaseAndNum[2]
   $NumArray = StringToASCIIArray($BaseNum)
   $Len = StringLen($basenum)
   For $i = 0 To $Len - 1
	  $output = $Output + int(chr($NumArray[$i]) * ($Base ^ (($Len - 1) - $i)))
   Next
   Return $Output
EndFunc

Правда никаких проверок на правильность ввода не делается (в условии этого нет)
 

C2H5OH

AutoIT Гуру
Сообщения
1,473
Репутация
333
Эээээ, нехорошо подсматривать чужой код...
Ты не используешь фишку ASCII, хотя и вызываешь
Код:
$NumArray = StringToASCIIArray($BaseNum)


Для твоих функций было бы логично использовать второй раз
Код:
$NumArray = StringSplit($BaseNum, "")


А потом вместо мудрёного
Код:
chr($NumArray[$i])

брать просто
Код:
$NumArray[$i]
 

xCite

Новичок
Сообщения
9
Репутация
0
Эээээ, нехорошо подсматривать чужой код...
Ты не используешь фишку ASCII, хотя и вызываешь
Код:
$NumArray = StringToASCIIArray($BaseNum)
тут да, согласен, я редиска)))
мне надо было вывести число по порядковому номеру в строке, но я не знаю как из строки вывести отдельный символ((
а тут смотрю - и библиотеки не подключаются, и работает как надо.
в общем плюсую тебе))

ЗЫ:
А потом вместо мудрёного
Код:
chr($NumArray[$i])

брать просто
Код:
$NumArray[$i]

из
Код:
chr($NumArray[$i])
получаю именно число (от 0 до 9)
а из
Код:
$NumArray[$i]
получается не число а код числа (0 это 48, 1 это 49 и т. д.)

В общем на что мозгов хватило... :whistle:


Добавлено:
Сообщение автоматически объединено:

Убрана похожесть на скрипт C2H5OH
Код:
$x1 = DecToN(200, 6)
$x2 = NToDec("4n10123012")
MsgBox (0, "", $x1)
MsgBox (0, "", $x2)

Func DecToN($DecNum, $Base)
   Local $Output = ""
   $Del = $DecNum
   While $Del > 0
	  $Ost = Mod($Del, $Base)
	  $Output = Chr(48 + $Ost) & $Output
	  $Del = Int($Del / $Base)
   WEnd
   $Output = $Base & "n" & $Output
   Return $Output
EndFunc

Func NToDec($Input)
   Local $Output = 0
   $BaseAndNum = StringSplit($Input, "n")
   $Len = StringLen($BaseAndNum[2])
   For $i = 0 To $Len - 1
	  $tmp = StringMid($BaseAndNum[2], $i+1, 1)
	  $Output = $Output + int($tmp) * ($BaseAndNum[1] ^ (($Len - 1) - $i))
   Next
   Return $Output
EndFunc
 

winstan

Эксплотатор)
Сообщения
406
Репутация
79
Код:
$j=DecToN(18118,9)
ConsoleWrite($j&@CRLF)
ConsoleWrite(NToDec($j)&@CRLF)

Func DecToN($decnum, $base)
	$ret=""
	While Not $decnum=0
		$t=Mod($decnum,$base)
		$decnum=Floor($decnum/$base)
		$ret=$t&$ret
	WEnd
	$ret=$base&"n"&$ret
Return $ret
EndFunc

Func NToDec($nnum)
	$t=StringSplit($nnum,"n",1)
	$arry=StringSplit($t[2],"")
	$ret=0
	For $i=1 To $arry[0]
		$y=$arry[0]-$i
		$ret+=$arry[$i]*$t[1]^$y
	Next
	Return $ret
EndFunc
 
Автор
kaster

kaster

Мой Аватар, он лучший самый
Команда форума
Глобальный модератор
Сообщения
4,020
Репутация
626
Вобщем, все решили правильно. я надеюсь, никто не обидится если за скоростью исполнения признаю победителем нашего этилового друга :smile:

вот мое решение. отличие от ваших решений - я не использовал конвертацию в ascii, зато использовал богоподобную рекурсию 8)

Код:
Func DecToN($decnum, $base)
	Return $base & 'n' & DecToNRec($decnum, $base)
EndFunc

Func DecToNRec($decnum, $base)
	If $decnum < $base Then
		Return $decnum
	Else
		$decint = Floor($decnum/$base)
		$rem = Mod($decnum, $base)
		Return DecToNRec($decint, $base) & $rem
	EndIf
EndFunc

Func NToDec($nnum)
	$nnum = StringSplit($nnum, 'n')
	$base = $nnum[1]
	$nnum = $nnum[2]
	$n = StringLen($nnum)
	$decnum = 0
	For $i = 1 to $n
		$decnum += Int(StringMid($nnum, $i, 1))*$base^($n - $i)
	Next
	Return $decnum
EndFunc

$decnum = 18118
For $i = 2 to 9
	ConsoleWrite($i & ':' & @TAB & DecToN($decnum, $i) & @CRLF)
Next
 

AZJIO

Меценат
Меценат
Сообщения
2,874
Репутация
1,194
Код:
$re=''
For $i = 2 To 9
	$re &= _DecToN('18118', $i)&@LF
Next
$re=StringTrimRight($re, 1)
MsgBox(0, 'Сообщение', $re)

$aNum=StringSplit($re, @LF)
$re=''
For $i = 1 To $aNum[0]
	$re &= _NToDec($aNum[$i])&@LF
Next
MsgBox(0, 'Сообщение', $re)

Func _DecToN($decnum, $base)
	Local $Out, $ost
	Do
		$ost=Mod($decnum, $base)
		$decnum=($decnum-$ost)/$base
		$Out=$ost&$Out
	Until $decnum=0
	Return $base&'n'&$Out
EndFunc

Func _NToDec($nnum)
	Local $aNum, $i, $n, $Out
	$aNum=StringSplit($nnum, 'n')
	If @error Or Not IsArray($aNum) Or $aNum[0]<>2 Then Return SetError(1)
	$n=StringSplit($aNum[2], '')
	For $i = 1 To $n[0]
		$Out += $n[$i]*$aNum[1]^($n[0]-$i)
	Next
	Return $Out
EndFunc


до шестнадцатеричных
Код:
$re=''
For $i = 2 To 16
	$re &= _DecToN('255', $i)&@LF
Next
$re=StringTrimRight($re, 1)
MsgBox(0, 'Сообщение', $re)

$aNum=StringSplit($re, @LF)
; #include <Array.au3>
; _ArrayDisplay($aNum, 'Array')
$re=''
For $i = 1 To $aNum[0]
	$re &= $aNum[$i] & ' - ' & _NToDec($aNum[$i])&@LF
Next
MsgBox(0, 'Сообщение', $re)

Func _DecToN($decnum, $base)
	Local $Out, $ost, $n[16]=['0','1','2','3','4','5','6','7','8','9','A','B','C','D','E','F']
	Do
		$ost=Mod($decnum, $base)
		$decnum=($decnum-$ost)/$base
		$Out=$n[$ost]&$Out
	Until $decnum=0
	Return $base&'n'&$Out
EndFunc

Func _NToDec($nnum)
	Local $aNum, $i, $n, $Out
	$aNum=StringSplit($nnum, 'n')
	If @error Or Not IsArray($aNum) Or $aNum[0]<>2 Then Return SetError(1)
	If StringRegExp($aNum[2], '(?i)[A-F]') Then
		$aNum[2]=StringRegExpReplace($aNum[2], '.', '\0,')
		$aNum[2]=StringTrimRight($aNum[2], 1)
		$aNum[2]=StringReplace($aNum[2], 'A', '10')
		$aNum[2]=StringReplace($aNum[2], 'B', '11')
		$aNum[2]=StringReplace($aNum[2], 'C', '12')
		$aNum[2]=StringReplace($aNum[2], 'D', '13')
		$aNum[2]=StringReplace($aNum[2], 'E', '14')
		$aNum[2]=StringReplace($aNum[2], 'F', '15')
		$n=StringSplit($aNum[2], ',')
	Else
		$n=StringSplit($aNum[2], '')
	EndIf
	For $i = 1 To $n[0]
		$Out += $n[$i]*$aNum[1]^($n[0]-$i)
	Next
	Return $Out
EndFunc
 
Верх