Основы работы с числами
Основы работы с числами в языке Dart
В Dart есть встроенные типы данных — built-in types.
Сегодня мы рассмотрим работу с числами и основные операции над ними.
В Dart есть два типа чисел: целые (int) и дробные (double). На виртуальной машине Dart (Dart VM) int может хранить целые числа до 64 бит. теоретически это от -9223372036854775808 до 9223372036854775807. Не забывайте, что один бит уходит на знак числа, поэтому максимальное значение int равно 2^63 - 1. Ещё мы теряем на запятой в double, поэтому максимальное значение double равно скорее 1.7976931348623157E+308 или (2^52). И если мы компилируем для веб-приложения в javascript, то должны знать, что int там теряет точность после 2^53.
Рассмотрим их на практике.
Приложение на Dart начинается с метода main
, который является основным методом приложения.
Метод main
— это точка входа в приложение. Здесь начинается выполнение программы.
void main() {
}
В этом методе мы можем сразу написать небольшой код либо вызвать другие методы или функции. В Dart методы — это функции, которые определяются внутри классов, но в контексте базового примера различие не столь важно. Мы подробнее рассмотрим это различие при углубленном изучении ООП.
Итак, в методе main
мы можем объявить пару переменных и, например, сложить их.
void main() {
int a = 5;
int b = 3;
int sum = a + b;
print(sum);
}
Если вывод результата сложения двух чисел занимает 4 строчки, то небольшое приложение, например, погоды, может занять и несколько тысяч строк.
Чтобы разобраться с этими строчками, мы работаем с различными функциями, которые логически отделены друг от друга.
void main() {
addInts();
addDoubles();
}
void addInts() {
int a = 5;
int b = 3;
int sum = a + b;
print("Результат сложения целых чисел: $sum");
}
void addDoubles() {
double a = 5.5;
double b = 3.4;
double sum = a + b;
print("Результат сложения десятичных чисел: $sum");
}
В методе main
вызываются две функции: addInts
и addDoubles
. Одна складывает заранее определенные целые числа, другая — десятичные.
Многие считают, что в человеческом понимании числа не делятся на числа с запятой и без. На самом деле это не совсем так. Для компьютера важно различать целые и дробные числа, поскольку операции с ними могут отличаться.
Теперь давайте реализуем простой калькулятор, чтобы понять, как работает ввод данных от пользователя.
import 'dart:io'; // Эта строчка очень важна, без неё не будет работать ввод данных
// Функция сложения двух чисел
double addNumbers(double a, double b) {
return a + b;
}
double userInput(order) {
stdout.write("Введите $order число: ");
double num = double.parse(stdin.readLineSync()!);
return num;
}
void main() {
// Запрос первого числа
double num1 = userInput("первое");
// Запрос второго числа
double num2 = userInput("второе");
// Вычисление и вывод результата
double result = addNumbers(num1, num2);
print("Сумма: $result");
}
После запуска в терминале у нас будет примерно такой вывод:
Введите число: 12
Введите число: 13
Сумма: 25.0
- Мы создали функцию
addNumbers
, которая принимает два числа и возвращает их сумму. - Функция
userInput
запрашивает у пользователя ввод числа и возвращает его. - В методе
main
мы вызываем функциюuserInput
дважды, чтобы получить два числа, складываем их и выводим результат.
- Мы переиспользовали одну функцию дважды.
- Мы сделали функции универсальными: каждый раз пользователь может вводить разные числа.
- Работа с вводом пользователя тоже достаточно универсальна.
- И мы сделали свой первый калькулятор. Абсолютно простейший, как амёба, но он работает, и это наш калькулятор.
Давайте посмотрим, что ещё мы можем делать с числами.
void main() {
int a = 123456789;
print(a);
double b = 0.123456;
print(b);
}
Нижние подчеркивания игнорируются компьютером, они просто для удобного чтения. Большие числа, как 4611686018427387904, тяжело прочитать. Нижние подчеркивания не так давно вошли практически во все языки программирования. В Java они более 10 лет, в JS — около 5 лет.
У нас есть возможность простой работы с шестнадцатеричной системой счисления.
Работа с различными системами счисления
Используется префикс 0x:
void main() {
int hexValue = 0x100; // 256 в десятичной системе
print(hexValue); // Выведет: 256
}
Для работы в других системах надо использовать метод toRadixString:
// Binary (base 2).
print(12.toRadixString(2)); // 1100
print(31.toRadixString(2)); // 11111
print(2021.toRadixString(2)); // 11111100101
print((-12).toRadixString(2)); // -1100
// Octal (base 8).
print(12.toRadixString(8)); // 14
print(31.toRadixString(8)); // 37
print(2021.toRadixString(8)); // 3745
// Hexadecimal (base 16).
print(12.toRadixString(16)); // c
print(31.toRadixString(16)); // 1f
print(2021.toRadixString(16)); // 7e5
// Base 36.
print((35 * 36 + 1).toRadixString(36)); // z1
Простые вычисления с помощью Dart
Но давайте вернёмся к обычной десятичной системе счисления. И посмотрим как мы можем решать к примеру обычные школьные задачи с помощью Dart.
Сложение и вычитание чисел
void main() {
int a = 5;
int b = 3;
int sum = a + b;
int diff = a - b;
print("Сумма: $sum");
print("Разность: $diff");
}
Умножение и деление чисел
void main() {
int a = 5;
int b = 3;
int product = a * b;
int quotient = a / b;
print("Произведение: $product");
print("Частное: $quotient");
}
Умножение и деление дробных чисел
void main() {
double a = 5.5;
double b = 3.4;
double product = a * b;
double quotient = a / b;
print("Произведение: $product");
print("Частное: $quotient");
}
Давайте посмотрим, что ещё мы можем делать с числами.
void main() {
const double pi = 3.14;
// const - используется для объявления константы,
// теперь переменной PI нельзя присвоить другое значение.
double r = 5.5;
double k = r * r;
double s = pi * r * r;
print(k);
// промежуточный результат
print(s);
}
Обратите внимание на то, что const не даёт изменить значение переменной. Для тех, кто имеет опыт программирования, обратите внимание, что pi пишется в нижнем регистре, а не с заглавной буквы. "Constants in Dart are written in lowercase_with_underscores."
Экспоненциальная запись
Экспоненциальная запись — представление действительных чисел в виде мантиссы (дробной части логарифма числа) и порядка. Удобна при представлении очень больших и очень малых чисел, а также для унификации их написания.
void main() {
double a = 1.42e5; // 142000.0
double b = 1.42e-5; // 0.0000142
print(a);
print(b);
}
Достаточно интересный вопрос: что происходит при пересечении разных типов данных? Что произойдёт, если тип переменных int встретится с double? Программа ниже демонстрирует, как ведут себя разные типы данных в Dart.
import 'dart:math';
void main() {
int var1 = 5;
int var2 = 2;
int var3 = var1 ~/ var2;
double var4 = 5.0;
double var5 = 2.0;
double var6 = var4 / var5;
double var7 = var1 / var2;
double var25 = var1 / var4;
print("Int Var3 = \$var3");
print("double Var6 = \$var6");
print("double Var7 = \$var7");
print("double Var25 = \$var25");
int var11 = (var1 / var4).toInt();
print("Int Var11 = \$var11");
print("Магия = \${5.0 / var2}");
}
- Оператор деления "/" возвращает всегда double.
- Оператор "~/" возвращает целую часть от деления и позволяет работать с int.
Результаты работы программы показывают, что переменная типа int может автоматически использоваться в расчётах с double. Однако обратное преобразование требует явного преобразования (casting), как в случае с var11
.
Теперь рассмотрим генерацию случайного числа от 30 до 100 в Dart. В отличие от Java, где используется Math.random()
, в Dart есть класс Random()
:
void main() {
int min = 30;
int max = 100;
int result = Random().nextInt(15);
double doubleValue = Random().nextDouble();
int secureResult = Random().secure().nextInt(10);
print("Случайное число: \$result");
}
Метод secure() использует такие источники, что делает число, сгенерированное этим методом, трудно предсказуемым даже если злоумышленник имеет доступ к предыдущим числам.
Округление чисел
В Dart существует несколько способов округления чисел, в том числе с помощью методов ceil()
, floor()
, round()
, и truncate()
. Давайте рассмотрим каждый из них на практике.
Метод ceil()
Метод ceil()
округляет число в большую сторону до ближайшего целого числа.
Пример:
void main() {
double num = 3.2;
print(num.ceil()); // 4
}
Метод floor()
Метод floor()
округляет число в меньшую сторону до ближайшего целого числа.
Пример:
void main() {
double num = 3.8;
print(num.floor()); // 3
}
Метод round()
Метод round()
округляет число до ближайшего целого. Если дробная часть числа меньше 0.5, число округляется в меньшую сторону, если больше или равно 0.5 — в большую сторону.
Пример:
void main() {
double num1 = 3.4;
double num2 = 3.5;
print(num1.round()); // 3
print(num2.round()); // 4
}
Метод truncate()
Метод truncate()
удаляет дробную часть числа и оставляет только целую. Это можно рассматривать как округление к нулю.
Пример:
void main() {
double num = 3.8;
print(num.truncate()); // 3
}
Возведение в степень
В Dart возведение в степень выполняется с помощью оператора pow
из библиотеки dart:math
. Он позволяет возвести число в степень и возвращает результат в виде числа типа double
. Рассмотрим пример использования.
Пример возведения в степень:
import 'dart:math';
void main() {
double base = 2;
int exponent = 3;
double result = pow(base, exponent);
print("Результат: $result"); // 8.0
}
Здесь мы используем функцию pow(base, exponent)
, где base
— основание, а exponent
— показатель степени. В данном примере основание 2
возводится в степень 3
, и результат равен 8.0
.
Использование с целыми числами
Важно отметить, что результат всегда будет типа double
, даже если основание и показатель степени — целые числа. Например:
import 'dart:math';
void main() {
int base = 2;
int exponent = 3;
double result = pow(base, exponent);
print("Результат: $result"); // 8.0
}
Если вам нужно получить целое число, можно использовать приведение типов:
import 'dart:math';
void main() {
int base = 2;
int exponent = 3;
int result = pow(base, exponent).toInt();
print("Результат: $result"); // 8
}
Домашнее задание
Может показаться, что слишком много математики, да и домашнего задания, но нам за один урок надо повторить математику средней школы. И скорее всего, этого даже недостаточно для среднего новичка. Поэтому решайте сами, как глубоко вам нужно. Я рекомендую выделить пару часов и прорешать все или хотя бы большинство задач.
1. Найти площадь и периметр квадрата.
Задайте сторону квадрата и вычислите его площадь и периметр, используя тип данных int
или double
.
calculateSquare(4) → "Площадь: 16, Периметр: 16"
calculateSquare(5.5) → "Площадь: 30.25, Периметр: 22.0"
2. Найти площадь и периметр прямоугольника. Для прямоугольника задайте длину и ширину, и вычислите его площадь и периметр.
calculateRectangle(4, 5) → "Площадь: 20, Периметр: 18"
calculateRectangle(3.5, 6) → "Площадь: 21.0, Периметр: 19.0"
3. Найти площадь и периметр куба.
Задайте длину ребра куба и вычислите площадь его поверхности и объём, используя тип данных double
или int
.
calculateCube(3) → "Площадь: 54, Объем: 27"
calculateCube(2.5) → "Площадь: 37.5, Объем: 15.625"
4. Вычисление площади круга
Напишите программу, которая принимает радиус круга и выводит его площадь. Для вычисления используйте формулу S = π * r^2
, где r радиус круга, а pi — математическая константа.
calculateCircleArea(5) → "Площадь: 78.53981633974483"
calculateCircleArea(2.5) → "Площадь: 19.634954084936208"
5. Длина окружности
Напишите программу, которая по заданному радиусу круга находит его длину. Для вычисления используйте формулу L = 2 * pi * r
, где r — радиус круга.
calculateCircleLength(5) → "Длина: 31.41592653589793"
calculateCircleLength(2.5) → "Длина: 15.707963267948966"
6. Конвертер валют Напишите программу, которая переводит сумму в долларах в евро. Известно, что курс евро к доллару составляет 1.1. Программа должна принимать на вход сумму в долларах и выводить эквивалент в евро.
convertDollarsToEuros(100) → "Евро: 110.0"
convertDollarsToEuros(50.5) → "Евро: 55.55"
7. Сравнение площадей стран Рассчитайте, во сколько раз площадь Беларуси больше площади Украины. Площадь Беларуси — 207,600 км², площадь Украины — 603,500 км². Программа должна вывести результат в виде целого числа.
8. Площадь городов Сравните площадь Москвы и Берлина. Площадь Москвы — 2,511 км², площадь Берлина — 891.8 км². Найдите, во сколько раз площадь Москвы больше площади Берлина.
9. Проценты в банке (Простой процент)
Если клиент положил в банк 1000 евро под 3.5% годовых, рассчитайте, сколько денег будет на его счету через 7 лет. Для этого используйте формулу простого процента:
S = P * (1 + (r-t)/100)
, где P — начальная сумма, r — процентная ставка, t — количество лет.
Задачи повышенной сложности
10. Проценты в банке (Сложный процент)
Если клиент положил 1000 евро под 3.5% годовых с капитализацией раз в год, рассчитайте, сколько денег будет на его счету через 7 лет. Для этого используйте формулу сложного процента:
S = P * (1 + r)/100)^t
, где P — начальная сумма, r — процентная ставка, t — количество лет.
11. Найти количество зёрен на шахматной доске. Шахматная доска состоит из 64 клеток. На первую клетку положите одно зёрнышко, на вторую — два, на третью — четыре и так далее, удваивая количество зёрен на каждой следующей клетке. Напишите программу, которая вычислит общее количество зёрен на всей доске.
Дополнительные ссылки
- num class
- Match class
- Effective Dart: Style
- Dart:math library
- Bit - https://en.wikipedia.org/wiki/Bit
- Системы счисления
- Легенда о шахматах и зёрнах