Прогулка вторая. Под яблоней.

Goржусь тобой, мой друг, за то, что ты решился продолжить изучение Go.
Сегодня речь пойдет о математике. Арифметические типы, как правило, самые простые, а арифметические задачи позволяют «пощупать» основные конструкции языка — ветвления, циклы.

Типы данных

Go — язык со строгой типизацией, т.е. типы переменных фиксируются во время компиляции и с тех пор остаются неизменными. Стало быть, присваивать можно только однотипные данные и неявного преобразования типов нет.
Числа в go представляются следующими типами:

  • Знаковое целое: int, int8, int16, int32, int64
  • Беззнаковое целое: uint, uint8, uint16, uint32, uint64
  • С плавающей точкой: float, float32, float64
  • Комплексные числа: complex, complex64, complex128 — берут за основу float32 и float64 соответственно

Вместо int8 можно использовать его псевдоним — byte. Важно заметить, что все это — различные типы. int — это не то же самое, что и int32, как привыкли любители C (и очень напрасно привыкли!). Размеры int, uint, float и соответственно complex зависят от платформы и на них полагаться нельзя.

Также go предоставляет тип uintptr для хранения адресов указателей — тоже скользкий платформо-зависимый тип.

Переменные

Оговорюсь немного о синтаксисе. Комментарии как обычно — «//» или «/*…*/». Точки с запятыми ставить можно, но не обязательно. Они отделяют выражения (но не служат признаком конца выражения). Короче, ставим «;» только если пишем несколько выражений на одной строке. Иначе go сам поймет.

Итак, давайте пообъявляем переменные. Для этого есть ключевое слово var. И назло всем C-шным программистам имя переменной и её тип пишутся наизнанку:

var x int
var y float = 1.234
var i, j, k int = 0, 1, 2

Уже выглядит заманчиво, но вы еще не готовы простить эту арабскую запись? Хорошо. Тип писать не обязательно если сразу присваиваете значение. Тип подхватится автоматически:

var x = 5 // это int
var y = 5.0 // это float
var p, q = 3, 3.0 // p-int, q-float

Тоже мало? Можно писать один var на целый блок переменных:

var (
  x = 3
  y, z = 1.1, 1.2
)

Все еще сердитесь? Ладно, не пишите вы этот var, если не хотите. Используйте старый добрый паскалевский «:=». Он заменяет var без явного указания типа.

x:=3
y:=x

Так-то. Все для людей программистов.

Намылить, смыть, повторить

Здесь говорить особо не о чем. Условный оператор выглядит как в C/Java, только без скобок. Зато, кстати, фигурные скобки обязательны. Условие в if-ах должно задаваться булевым значением (не целым числом, как в C).
К слову, в go есть тип bool со значениями true/false. Так вот, операторы которые дают булевский результат такие же как и в большинстве языков: ==, !=, <, <=, >, >=

if x == 0 { 
  return true
} else {
  return false
}

Все циклы основаны на одном ключевом слове — for. Он же и условный цикл, и цикл со счетчиком. Например:

for x < 100 {
  x *= 2
}
for i:=0; i<100; i++ { ... }
for { ... }  // Как раньше for (;;) или while (1)

Обратите внимание на i:=0 — здесь неявное объявление переменной пришлось очень кстати.

Функции

Для объявления функции используют ключевое слово func, возвращаемое значение пишем наизнанку, как и типы переменных. В остальном все как большинстве языков:

func max(a, b int) int {
  if a > b {
    return a
  }
  return b
}

Поехали!

А давайте-ка реализуем Ньютоновский метод для расчета корня квадратного. Также известен как метод касательных.
Общая его идея сводится к поиску Xi+1 = (Xi + N / Xi) / 2. Здесь N — число, из которого извлекаем корень, а X — постоянно стремится к значению корня.

func NewtonSqrt(n int) int {
	if (n <= 0) { return 0 }
	x := n
	res := n
	for {
		x = (x + n / x) / 2
		if res > x {
			res = x
		} else {
			break
		}
	}
	return x;
}

Все как я и рассказывал — функции, условия, циклы, break и continue есть как и во всех языках. Про goto тоже не забыли. Как вы уже заметили, операции над числами проводятся так же, как и в C/Java — те же +, -, *, /, %.
Допускаются +=, -= и им подобные, есть логические и бинарные &, &&, |, ||, ^.

Замечу, что оператора «~» нет. Вместо него используйте «^». Ну логично же: инверсия — это XOR с нулем!
Зато добавили хитрый оператор &^ — очистить биты (И-НЕ). Даже можно использовать «&^=».

Еще, еще математики!

Хотите еще функций? Сейчас. Вы заметили слово package в hello world в первом уроке? Оно определяет к какому пакету относится тот или иной модуль. В дальнейшем, существующие модули можно подключать и использовать их функции. Есть, разумеется и стандартные модули. Например, уже встречающийся нам fmt. Он отвечает за форматированный ввод/вывод (как в printf/scanf). Для математики подключаем модуль math:

package main
import "fmt"
import "math"
...

Если модулей много, можно объединить их все в общий import (помните, мы так с var делали?)

import (
  "fmt"
  "math"
)

Документация по стандартным модулям лежит здесь.

Итоги

А давайте сравним системный sqrt и наш. Вот такая у нас программа получилась:

package main

import (
	"fmt"
	"math"
)

func NewtonSqrt(x int) int {
	if (x <= 0) { return 0 }

	div := x
	res := x

	for {
		div = (x / div + div) / 2
		if res > div {
			res = div
		} else {
			break
		}
	}
	return res;
}

func SystemSqrt(x int) int {
	return int(math.Sqrt(float64(x)))
}

func main() {
	for x := 4; x<100000; x*=2 {
		fmt.Printf("%6d: %4d %4d\n", x, NewtonSqrt(x), SystemSqrt(x));
	}
}

Обратите внимание на math.Sqrt(). Эта функция принимает аргументом float64. Такой же тип и возвращает. А мы работаем с int. Конвертировать числовые переменные можно с помощью функций, совпадающих с именем типа — int, float64 и других.
Наша программа выводит ясное подтверждение того, что Ньютон был прав в своей формуле приближенного расчета корня квадратного:

     4:    2    2
     8:    2    2
    16:    4    4
    32:    5    5
    64:    8    8
   128:   11   11
   256:   16   16
   512:   22   22
  1024:   32   32
  2048:   45   45
  4096:   64   64
  8192:   90   90
 16384:  128  128
 32768:  181  181
 65536:  256  256

Довольны? Ну, до скороGo!


Домашнее задание

Вспомните университетские деньки и реализуйте какой-нибудь метод, например:

  • Евклида для нахождения наибольшего общего делителя
  • Деления пополам для нахождения минимума функции
  • Золотого сечения
  • Решета Эратосфена для нахождения простых чисел
  • …ну или чему вас там учили
Реклама

Добавить комментарий

Заполните поля или щелкните по значку, чтобы оставить свой комментарий:

Логотип WordPress.com

Для комментария используется ваша учётная запись WordPress.com. Выход / Изменить )

Фотография Twitter

Для комментария используется ваша учётная запись Twitter. Выход / Изменить )

Фотография Facebook

Для комментария используется ваша учётная запись Facebook. Выход / Изменить )

Google+ photo

Для комментария используется ваша учётная запись Google+. Выход / Изменить )

Connecting to %s