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;
|
263
lib/main.dart
263
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,43 +46,46 @@ class _MyHomePageState extends State<MyHomePage> {
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
return Scaffold(
|
return GestureDetector(
|
||||||
appBar: AppBar(
|
onTap: () => hidekbd,
|
||||||
title: const Text("Base Converter"),
|
child: Scaffold(
|
||||||
actions: [
|
appBar: AppBar(
|
||||||
IconButton(
|
title: const Text("Base Converter"),
|
||||||
onPressed: () => {
|
actions: [
|
||||||
showDialog(
|
IconButton(
|
||||||
context: context,
|
onPressed: () => {
|
||||||
builder: (BuildContext context) {
|
showDialog(
|
||||||
return AlertDialog(
|
context: context,
|
||||||
title: const Text("How to use:"),
|
builder: (BuildContext context) {
|
||||||
content: const Text(
|
return AlertDialog(
|
||||||
"Input the number you want to convert, select the base it is in and the base you want convert it into. Then click \"Calculate\" and the result will appear at the bottom of the screen!",
|
title: const Text("How to use:"),
|
||||||
style: TextStyle(fontSize: 13),
|
content: const Text(
|
||||||
),
|
"Input the number you want to convert, select the base it is in and the base you want convert it into. Then click \"Calculate\" and the result will appear at the bottom of the screen!",
|
||||||
contentPadding:
|
style: TextStyle(fontSize: 13),
|
||||||
const EdgeInsets.fromLTRB(24, 16, 24, 8),
|
),
|
||||||
actions: [
|
contentPadding:
|
||||||
TextButton(
|
const EdgeInsets.fromLTRB(24, 16, 24, 8),
|
||||||
onPressed: () => {Navigator.pop(context)},
|
actions: [
|
||||||
child: Row(
|
TextButton(
|
||||||
mainAxisAlignment:
|
onPressed: () => {Navigator.pop(context)},
|
||||||
MainAxisAlignment.center,
|
child: Row(
|
||||||
children: const [Text("Close")]))
|
mainAxisAlignment:
|
||||||
]);
|
MainAxisAlignment.center,
|
||||||
}),
|
children: const [Text("Close")]))
|
||||||
},
|
]);
|
||||||
icon: const Icon(Icons.info_outline_rounded))
|
}),
|
||||||
],
|
},
|
||||||
),
|
icon: const Icon(Icons.info_outline_rounded))
|
||||||
body: SafeArea(
|
],
|
||||||
child: Container(
|
),
|
||||||
|
body: 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,53 +204,67 @@ class _MyHomePageState extends State<MyHomePage> {
|
||||||
const SizedBox(
|
const SizedBox(
|
||||||
width: 10,
|
width: 10,
|
||||||
),
|
),
|
||||||
dpb(value),
|
DropdownButton<String>(
|
||||||
|
value: i == 0 ? fromBase : toBase,
|
||||||
|
icon: const Icon(Icons.arrow_downward),
|
||||||
|
iconSize: 16,
|
||||||
|
elevation: 16,
|
||||||
|
style: const TextStyle(color: Colors.deepPurple),
|
||||||
|
underline: Container(
|
||||||
|
height: 2,
|
||||||
|
color: Colors.deepPurpleAccent,
|
||||||
|
),
|
||||||
|
onChanged: (String? newValue) {
|
||||||
|
setState(() {
|
||||||
|
if (i == 0) {
|
||||||
|
fromBase = newValue!;
|
||||||
|
} else if (i == 1) {
|
||||||
|
toBase = newValue!;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
},
|
||||||
|
items: items.map<DropdownMenuItem<String>>((String value) {
|
||||||
|
return DropdownMenuItem<String>(
|
||||||
|
value: value,
|
||||||
|
child: Text(value),
|
||||||
|
);
|
||||||
|
}).toList(),
|
||||||
|
),
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
DropdownButton dpb(String dropdownValue) {
|
List<String> items = <String>[
|
||||||
return DropdownButton<String>(
|
'1',
|
||||||
value: dropdownValue,
|
'2',
|
||||||
icon: const Icon(Icons.arrow_downward),
|
'3',
|
||||||
iconSize: 24,
|
'4',
|
||||||
elevation: 16,
|
'5',
|
||||||
style: const TextStyle(color: Colors.deepPurple),
|
'6',
|
||||||
underline: Container(
|
'7',
|
||||||
height: 2,
|
'8',
|
||||||
color: Colors.deepPurpleAccent,
|
'9',
|
||||||
),
|
'10',
|
||||||
onChanged: (String? newValue) {
|
'11',
|
||||||
setState(() {
|
'12',
|
||||||
dropdownValue = newValue!;
|
'13',
|
||||||
});
|
'14',
|
||||||
},
|
'15',
|
||||||
items: <String>[
|
'Hex',
|
||||||
'One',
|
'BCD',
|
||||||
'Two',
|
"2CP"
|
||||||
'Three',
|
];
|
||||||
'Four',
|
|
||||||
'Five',
|
void calculate() {
|
||||||
'Six',
|
setState(() {
|
||||||
'Seven',
|
hidekbd();
|
||||||
'Eight',
|
savedFromBase = fromBase;
|
||||||
'Nine',
|
savedToBase = toBase;
|
||||||
'Ten',
|
|
||||||
'Eleven',
|
String s = baseToDecimal(_controller.text.toUpperCase(), savedFromBase);
|
||||||
'Twelve',
|
if (!s.startsWith("error")) s = decimalToBase(int.parse(s), savedToBase);
|
||||||
'Thirteen',
|
result = s;
|
||||||
'Fourteen',
|
});
|
||||||
'Fifteen',
|
|
||||||
'Hex',
|
|
||||||
'BCD',
|
|
||||||
'2\'s CP'
|
|
||||||
].map<DropdownMenuItem<String>>((String value) {
|
|
||||||
return DropdownMenuItem<String>(
|
|
||||||
value: value,
|
|
||||||
child: Text(value),
|
|
||||||
);
|
|
||||||
}).toList(),
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue