Conversions from bases 0-16, 2CP, BCD
parent
303094d6dc
commit
99f517d0ba
|
@ -0,0 +1,144 @@
|
||||||
|
import 'dart:math';
|
||||||
|
|
||||||
|
String decimalToBase(int number, toBase) {
|
||||||
|
//current base as integer
|
||||||
|
String tmpBase = toBase.toUpperCase();
|
||||||
|
if (tmpBase == "HEX") tmpBase = "16";
|
||||||
|
|
||||||
|
bool negative = number < 0;
|
||||||
|
if (negative) number *= -1;
|
||||||
|
|
||||||
|
String res = "";
|
||||||
|
switch (tmpBase) {
|
||||||
|
case "BCD":
|
||||||
|
String n = number.toString();
|
||||||
|
for (int i = 0; i < n.length; i++) {
|
||||||
|
String digit = decimalToBase(int.parse(n[i]), "2");
|
||||||
|
int missingZeros = 4 - digit.length;
|
||||||
|
for (int i = 0; i < missingZeros; i++) {
|
||||||
|
digit = "0" + digit;
|
||||||
|
}
|
||||||
|
res += digit;
|
||||||
|
}
|
||||||
|
if (negative) res = "-" + res;
|
||||||
|
break;
|
||||||
|
case "2CP":
|
||||||
|
String binary = decimalToBase(number, 2);
|
||||||
|
bool gotOne = false;
|
||||||
|
if (negative) {
|
||||||
|
for (int i = 0; i < binary.length; i++) {
|
||||||
|
if (gotOne) {
|
||||||
|
if (binary[i] == "1")
|
||||||
|
binary[i] == "0";
|
||||||
|
else
|
||||||
|
binary[i] == "1";
|
||||||
|
} else {
|
||||||
|
if (binary[i] == "1") gotOne = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
res = binary;
|
||||||
|
} else {
|
||||||
|
res = "0" + binary;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
int base = int.parse(tmpBase); //current base as integer
|
||||||
|
List<int> digits = [];
|
||||||
|
|
||||||
|
while (number != 0) {
|
||||||
|
digits.add(number % base);
|
||||||
|
number = number ~/ base;
|
||||||
|
}
|
||||||
|
digits = digits.reversed.toList();
|
||||||
|
|
||||||
|
for (int i = 0; i < digits.length; i++) {
|
||||||
|
if (digits[i] >= 10) {
|
||||||
|
res += String.fromCharCode(digits[i] + 55);
|
||||||
|
} else {
|
||||||
|
res += digits[i].toString();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (negative) res = "-" + res;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
|
String baseToDecimal(String number, String pBase) {
|
||||||
|
bool negative = number.startsWith('-');
|
||||||
|
if (negative) number = number.split('-')[1];
|
||||||
|
|
||||||
|
//current base as integer
|
||||||
|
String tmpBase = pBase.toUpperCase();
|
||||||
|
if (tmpBase == "HEX") tmpBase = "16";
|
||||||
|
|
||||||
|
String cBase = tmpBase;
|
||||||
|
if (cBase == "BCD" || cBase == "2CP") cBase = "2";
|
||||||
|
int controlBase = int.parse(cBase);
|
||||||
|
|
||||||
|
for (int i = 0; i < number.length; i++) {
|
||||||
|
if (charToDigit(number, i) >= controlBase) {
|
||||||
|
return "error-invalid-number-for-base";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
String res = "";
|
||||||
|
switch (tmpBase) {
|
||||||
|
case "BCD":
|
||||||
|
int missingZeros = (4 - number.length % 4) % 4;
|
||||||
|
for (int i = 0; i < missingZeros; i++) number = "0" + number;
|
||||||
|
|
||||||
|
for (int i = 0; i < number.length; i += 4) {
|
||||||
|
String n = number[i];
|
||||||
|
n += number[i + 1];
|
||||||
|
n += number[i + 2];
|
||||||
|
n += number[i + 3];
|
||||||
|
String n1 = baseToDecimal(n, "2");
|
||||||
|
print(n1);
|
||||||
|
if (int.parse(n1) > 9) return "error-bcd-greater-nine";
|
||||||
|
res += n1;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case "2CP":
|
||||||
|
if (negative) {
|
||||||
|
return "error-negative-cp2";
|
||||||
|
}
|
||||||
|
|
||||||
|
int dres = 0;
|
||||||
|
number = number.split('').reversed.join('').toString();
|
||||||
|
for (int i = 0; i < number.length; i++) {
|
||||||
|
int add = int.parse(number[i]) * pow(2, i).toInt();
|
||||||
|
if (i == number.length - 1) add *= -1;
|
||||||
|
dres += add;
|
||||||
|
}
|
||||||
|
res = dres.toString();
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
int base = int.parse(tmpBase);
|
||||||
|
List<int> digits = [];
|
||||||
|
|
||||||
|
// Get the value in decimal of the current digit
|
||||||
|
for (int i = 0; i < number.length; i++) {
|
||||||
|
int digit = charToDigit(number, i);
|
||||||
|
digits.add(digit);
|
||||||
|
}
|
||||||
|
|
||||||
|
//Reverse the list
|
||||||
|
digits = digits.reversed.toList();
|
||||||
|
|
||||||
|
int dres = 0;
|
||||||
|
for (int i = 0; i < digits.length; i++) {
|
||||||
|
dres += digits[i] * pow(base, i).toInt();
|
||||||
|
}
|
||||||
|
res = dres.toString();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
|
int charToDigit(String s, int i) {
|
||||||
|
return isDigit(s, i) ? int.parse(s[i]) : s.codeUnitAt(i) - 55;
|
||||||
|
}
|
||||||
|
|
||||||
|
// https://stackoverflow.com/questions/25872456/dart-what-is-the-fastest-way-to-check-if-a-particular-symbol-in-a-string-is-a-d
|
||||||
|
bool isDigit(String s, int i) => (s.codeUnitAt(i) ^ 0x30) <= 9;
|
181
lib/main.dart
181
lib/main.dart
|
@ -1,4 +1,7 @@
|
||||||
|
import 'package:flutter/cupertino.dart';
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
|
import 'package:flutter/widgets.dart';
|
||||||
|
import 'package:base_converter/calculations.dart';
|
||||||
|
|
||||||
void main() {
|
void main() {
|
||||||
runApp(const MyApp());
|
runApp(const MyApp());
|
||||||
|
@ -13,15 +16,6 @@ class MyApp extends StatelessWidget {
|
||||||
return MaterialApp(
|
return MaterialApp(
|
||||||
title: 'Base Converter',
|
title: 'Base Converter',
|
||||||
theme: ThemeData(
|
theme: ThemeData(
|
||||||
// This is the theme of your application.
|
|
||||||
//
|
|
||||||
// Try running your application with "flutter run". You'll see the
|
|
||||||
// application has a blue toolbar. Then, without quitting the app, try
|
|
||||||
// changing the primarySwatch below to Colors.green and then invoke
|
|
||||||
// "hot reload" (press "r" in the console where you ran "flutter run",
|
|
||||||
// or simply save your changes to "hot reload" in a Flutter IDE).
|
|
||||||
// Notice that the counter didn't reset back to zero; the application
|
|
||||||
// is not restarted.
|
|
||||||
primarySwatch: Colors.blue,
|
primarySwatch: Colors.blue,
|
||||||
),
|
),
|
||||||
home: const MyHomePage(),
|
home: const MyHomePage(),
|
||||||
|
@ -37,9 +31,8 @@ class MyHomePage extends StatefulWidget {
|
||||||
}
|
}
|
||||||
|
|
||||||
class _MyHomePageState extends State<MyHomePage> {
|
class _MyHomePageState extends State<MyHomePage> {
|
||||||
String fromBase = "One";
|
String fromBase = "2", savedFromBase = "";
|
||||||
String toBase = "One";
|
String toBase = "10", savedToBase = "";
|
||||||
|
|
||||||
String result = "";
|
String result = "";
|
||||||
|
|
||||||
late TextEditingController _controller;
|
late TextEditingController _controller;
|
||||||
|
@ -53,7 +46,9 @@ class _MyHomePageState extends State<MyHomePage> {
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
return Scaffold(
|
return GestureDetector(
|
||||||
|
onTap: () => hidekbd,
|
||||||
|
child: Scaffold(
|
||||||
appBar: AppBar(
|
appBar: AppBar(
|
||||||
title: const Text("Base Converter"),
|
title: const Text("Base Converter"),
|
||||||
actions: [
|
actions: [
|
||||||
|
@ -83,13 +78,14 @@ class _MyHomePageState extends State<MyHomePage> {
|
||||||
icon: const Icon(Icons.info_outline_rounded))
|
icon: const Icon(Icons.info_outline_rounded))
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
body: SafeArea(
|
body: Container(
|
||||||
child: Container(
|
|
||||||
margin: const EdgeInsets.fromLTRB(24, 32, 24, 32),
|
margin: const EdgeInsets.fromLTRB(24, 32, 24, 32),
|
||||||
child: Column(children: [
|
child: Column(children: [
|
||||||
mainBody(),
|
mainBody(),
|
||||||
Expanded(
|
Expanded(
|
||||||
child: Center(child: richText),
|
child: Container(
|
||||||
|
margin: const EdgeInsets.all(24),
|
||||||
|
child: Center(child: resultToRichText())),
|
||||||
)
|
)
|
||||||
]),
|
]),
|
||||||
),
|
),
|
||||||
|
@ -110,11 +106,11 @@ class _MyHomePageState extends State<MyHomePage> {
|
||||||
TextField(
|
TextField(
|
||||||
controller: _controller,
|
controller: _controller,
|
||||||
decoration: const InputDecoration(hintText: "Number "),
|
decoration: const InputDecoration(hintText: "Number "),
|
||||||
|
keyboardType: TextInputType.phone,
|
||||||
),
|
),
|
||||||
Row(mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [
|
Row(
|
||||||
baseSelector("From:", fromBase),
|
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||||
baseSelector("To:", toBase)
|
children: [baseSelector("From:", 0), baseSelector("To:", 1)]),
|
||||||
]),
|
|
||||||
Row(children: [
|
Row(children: [
|
||||||
Expanded(
|
Expanded(
|
||||||
child: TextButton(
|
child: TextButton(
|
||||||
|
@ -131,13 +127,74 @@ class _MyHomePageState extends State<MyHomePage> {
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
void calculate() {}
|
void hidekbd() {
|
||||||
|
FocusManager.instance.primaryFocus?.unfocus();
|
||||||
|
}
|
||||||
|
|
||||||
void decimalToBase() {}
|
RichText resultToRichText() {
|
||||||
|
switch (result) {
|
||||||
|
case "error-negative-in-cp2":
|
||||||
|
return errorString("Error: 2CP number can't have a negative sign");
|
||||||
|
case "error-bcd-greater-nine":
|
||||||
|
return errorString("Error: BCD can only code digits from 0 to 9");
|
||||||
|
case "error-invalid-number-for-base":
|
||||||
|
return errorString(
|
||||||
|
"Error: a digit is greater than or equal to the base");
|
||||||
|
case "":
|
||||||
|
return RichText(
|
||||||
|
text: TextSpan(
|
||||||
|
text: '',
|
||||||
|
style: DefaultTextStyle.of(context).style,
|
||||||
|
children: const <TextSpan>[],
|
||||||
|
),
|
||||||
|
);
|
||||||
|
default:
|
||||||
|
return RichText(
|
||||||
|
text: TextSpan(
|
||||||
|
text: '',
|
||||||
|
style: DefaultTextStyle.of(context).style,
|
||||||
|
children: <TextSpan>[
|
||||||
|
mainNumber(_controller.text),
|
||||||
|
baseSubtitle("($savedFromBase)"),
|
||||||
|
mainNumber(" = $result"),
|
||||||
|
baseSubtitle("($savedToBase)"),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void baseToDecimal() {}
|
RichText errorString(String content) {
|
||||||
|
return RichText(
|
||||||
|
text: TextSpan(
|
||||||
|
text: '',
|
||||||
|
style: DefaultTextStyle.of(context).style,
|
||||||
|
children: <TextSpan>[
|
||||||
|
TextSpan(
|
||||||
|
text: content,
|
||||||
|
style: const TextStyle(
|
||||||
|
color: Colors.black,
|
||||||
|
fontSize: 12,
|
||||||
|
fontWeight: FontWeight.normal,
|
||||||
|
fontFamily: "Roboto")),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
Container baseSelector(String labelText, String value) {
|
TextSpan mainNumber(String text) {
|
||||||
|
return TextSpan(
|
||||||
|
text: text,
|
||||||
|
style: const TextStyle(
|
||||||
|
color: Colors.black, fontSize: 18, fontWeight: FontWeight.bold));
|
||||||
|
}
|
||||||
|
|
||||||
|
TextSpan baseSubtitle(String text) {
|
||||||
|
return TextSpan(
|
||||||
|
text: text, style: const TextStyle(color: Colors.black, fontSize: 14));
|
||||||
|
}
|
||||||
|
|
||||||
|
Container baseSelector(String labelText, int i) {
|
||||||
return Container(
|
return Container(
|
||||||
margin: const EdgeInsets.all(4),
|
margin: const EdgeInsets.all(4),
|
||||||
child: Row(
|
child: Row(
|
||||||
|
@ -147,17 +204,10 @@ class _MyHomePageState extends State<MyHomePage> {
|
||||||
const SizedBox(
|
const SizedBox(
|
||||||
width: 10,
|
width: 10,
|
||||||
),
|
),
|
||||||
dpb(value),
|
DropdownButton<String>(
|
||||||
],
|
value: i == 0 ? fromBase : toBase,
|
||||||
),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
DropdownButton dpb(String dropdownValue) {
|
|
||||||
return DropdownButton<String>(
|
|
||||||
value: dropdownValue,
|
|
||||||
icon: const Icon(Icons.arrow_downward),
|
icon: const Icon(Icons.arrow_downward),
|
||||||
iconSize: 24,
|
iconSize: 16,
|
||||||
elevation: 16,
|
elevation: 16,
|
||||||
style: const TextStyle(color: Colors.deepPurple),
|
style: const TextStyle(color: Colors.deepPurple),
|
||||||
underline: Container(
|
underline: Container(
|
||||||
|
@ -166,34 +216,55 @@ class _MyHomePageState extends State<MyHomePage> {
|
||||||
),
|
),
|
||||||
onChanged: (String? newValue) {
|
onChanged: (String? newValue) {
|
||||||
setState(() {
|
setState(() {
|
||||||
dropdownValue = newValue!;
|
if (i == 0) {
|
||||||
|
fromBase = newValue!;
|
||||||
|
} else if (i == 1) {
|
||||||
|
toBase = newValue!;
|
||||||
|
}
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
items: <String>[
|
items: items.map<DropdownMenuItem<String>>((String value) {
|
||||||
'One',
|
|
||||||
'Two',
|
|
||||||
'Three',
|
|
||||||
'Four',
|
|
||||||
'Five',
|
|
||||||
'Six',
|
|
||||||
'Seven',
|
|
||||||
'Eight',
|
|
||||||
'Nine',
|
|
||||||
'Ten',
|
|
||||||
'Eleven',
|
|
||||||
'Twelve',
|
|
||||||
'Thirteen',
|
|
||||||
'Fourteen',
|
|
||||||
'Fifteen',
|
|
||||||
'Hex',
|
|
||||||
'BCD',
|
|
||||||
'2\'s CP'
|
|
||||||
].map<DropdownMenuItem<String>>((String value) {
|
|
||||||
return DropdownMenuItem<String>(
|
return DropdownMenuItem<String>(
|
||||||
value: value,
|
value: value,
|
||||||
child: Text(value),
|
child: Text(value),
|
||||||
);
|
);
|
||||||
}).toList(),
|
}).toList(),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
List<String> items = <String>[
|
||||||
|
'1',
|
||||||
|
'2',
|
||||||
|
'3',
|
||||||
|
'4',
|
||||||
|
'5',
|
||||||
|
'6',
|
||||||
|
'7',
|
||||||
|
'8',
|
||||||
|
'9',
|
||||||
|
'10',
|
||||||
|
'11',
|
||||||
|
'12',
|
||||||
|
'13',
|
||||||
|
'14',
|
||||||
|
'15',
|
||||||
|
'Hex',
|
||||||
|
'BCD',
|
||||||
|
"2CP"
|
||||||
|
];
|
||||||
|
|
||||||
|
void calculate() {
|
||||||
|
setState(() {
|
||||||
|
hidekbd();
|
||||||
|
savedFromBase = fromBase;
|
||||||
|
savedToBase = toBase;
|
||||||
|
|
||||||
|
String s = baseToDecimal(_controller.text.toUpperCase(), savedFromBase);
|
||||||
|
if (!s.startsWith("error")) s = decimalToBase(int.parse(s), savedToBase);
|
||||||
|
result = s;
|
||||||
|
});
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue