АПД судя по комментариям, эта статья нуждается в некоторой мотивировке. Что именно и зачем мы делаем. Коротко говоря, производную все, кто её как-то запоминает (а запоминают немногие) помнят в дальнейшем как «другой график». Это «ещё одна функция», которая описывает исходную. Мы никогда почти не интересуемся производной поточечно. А между тем производная изначально — не столько отдельная функция, сколько характеристика исходного графика в разных точках. Именно эту привязку мы и проявим в статье. КОНЕЦ АПД
ВТОРОЙ АПД о касательной как пределе секущих и другой возможной питонизации темы см. в длинном комментарии под статьёй вот тут: https://habr.com/ru/post/599051/#comment_23894499 . КОНЕЦ ВТОРОГО АПД
Начнём с повторения математических терминов и нескольких опций питона. В питоне мы будем использовать черепашку, а также модуль математических функций math. От черепашки понадобятся:
-
shape(), color(), speed(), radians() — функции общей настройки
-
xcor(), ycor() — функции, сообщающие положение
-
goto() — для перемещения черепашки в точку
-
setheading() — для изменения направления головы черепашки
-
done() — функция замораживания экрана (нужна при работе в трезвом редакторе вроде VSCode. Если вы пишете в IDLE, она не нужна)
Кроме того, заметим, что поле у черепашки в пикселях. Если она побежит по параболе — убежит моментально за край листка. Так что введём какую-нибудь единицу UNIT = 100 пикселей, например, ну и вот это вот всё отнормируем в наших юнитах.
Из модуля math возьмём функцию atan() — арктангенс. Она возвращает радианную меру угла, не градусы. Дальше мы либо там же берём число pi — константу модуля math, тихо на неё делим, умножив потом на 180, либо мы повторяем, что значит «радианная мера угла», вернее — проходим её. Ваши ученики, скорее всего, про радианы не слышали.
А «производная» в данном случае — «тангенс угла наклона касательной», вот, что нам требуется. Очень похоже на канцелярит, «нанизывание родительных падежей» — «зам. главы отдела контроля качества цеха упаковки (и др.)». Будем эту конструкцию разбирать с конца:
-
есть у нас график функции y = f(x)
-
есть на нём точка, (a, f(a))
-
если туда пришла черепаха, если она (черепаха) бежит по графику, ей в этой точке надо смотреть… по касательной к графику, так что нам требуется уравнение этой касательной. Если последнее записать как y = kx+b, то это k как раз и есть производная: k = f'(a)
-
функция перенаправления головы черепашки умеет в углы, не в прямые. Чтобы сказать «посмотри в направлении этой прямой» мы должны передать не прямую, а «угол между прямой, по которой надо смотреть, и лучом Ox». И если k в пункте выше — тангенс того угла, тут нам понадобится арктангенс k: atan(f'(a))
Получим что-то такое вот для параболы:
from turtle import Turtle, done from math import atan UNIT = 100 alice = Turtle() alice.color('green') alice.shape('turtle') alice.speed(1) alice.radians() for step in range(2 * UNIT): x = alice.xcor() + 1 y = x**2 / UNIT alice.goto(int(x), int(y)) k = 2*x / UNIT alpha = atan(k) alice.setheading(alpha) done()
Что-то подобное я уже делала с несколькими +/- старшеклассниками. В целом неплохо: это можно прочесть, и код работает (проверьте сами). В чём тут проблемы:
-
не вполне ясно, где мы тут делим на юнит, как выбраны эти места
-
что нам придётся делать с юнитами, когда мы заменим график
-
можно ли всю картинку сдвинуть из точки (0, 0)?
-
как пересадить это в браузер с джаваскриптом и стилями?
В браузере мы можем создать картинку с помощью трёх div-ов: внешний со срезанными углами и глазками (это два вложенных div). Глазки куда-нибудь смещены, надо их перенаправить по курсу. Перемещать можно с помощью javascript:
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta http-equiv="X-UA-Compatible" content="IE=edge"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <style> body { background: gray; } .beast { position: absolute; background: green; width: 20px; height: 20px; border-radius: 50%; } .eye { background: white; width: 5px; height: 5px; border-radius: 2px; transform: translateY(5px); } </style> </head> <body> <div class="beast"> <div class="eye"></div> <div class="eye"></div> </div> <script> const UNIT = 100 const beast = document.getElementsByClassName('beast')[0] let x = 0 let y = 0 let k = 0 let alpha = 0 let id = setInterval( function() { x++ y = x * x / UNIT beast.style.left = x + 'px' beast.style.top = y + 'px' k = 2 * x / UNIT alpha = Math.atan(k) * 180 / Math.PI + 180 beast.style.transform = 'rotate(' + alpha + 'deg)' if (x > 2 * UNIT) clearInterval(id) }, 50 ) </script> </body> </html>
С этого места код хочется разделить на файлы. Собственно, и питоновский код тоже хочется, и мы делили его: файл с основной логикой + файл отрисовка + файл калькулятор. В браузере, соответственно, плюс ещё два файла: разметка и стили.
Бонусом станет возможность на этом же материале пройти наследование. Или даже уже интерфейсы. Вы пишете интерфейс для воплощения функции и производной. Функционал отрисовки юзает интерфейс. А ваши классы с разными калькуляторами обсчитывают разные функции.
Пример с наследованием, примерно в таком вот виде пройденный с восьмиклассником в начале учебного года (парень — сын программиста, и увлекается программированием давно). У нас есть главный файл с основной логикой, рисовалка и папка с разными калькуляторами: базовым и наследующими под разные функции.
main.py
from painter import Painter from calculators.calculatorSquare import CalculatorSquare painter = Painter() calculator = CalculatorSquare() for x in range(200): calculator.nextStep() y = calculator.getY() alpha = calculator.getAngleInRadians() painter.showState(x, y, alpha) painter.freeze()
painter.py
class Painter: def __init__(self): from turtle import Turtle, Screen self.__beast = Turtle() self.__beast.shape('turtle') self.__beast.speed(10) self.__beast.radians() def showState(self, x, y, alpha): self.__beast.goto(x,y) self.__beast.setheading(alpha) def freeze(self): from turtle import done done()
и папка calculators с файлами calculator.py
from math import atan class Calculator: def __init__(self): self._UNIT = 100 self._x = 0 self._y = 0 self._alpha = 0 def nextStep(self): self._x += 1 def getY(self) -> float: pass def getDerivative(self) -> float: pass def getAngleInRadians(self) -> float: return atan(self.getDerivative())
и calculatorSquare.py
from .calculator import Calculator class CalculatorSquare(Calculator): def getY(self): return self._x ** 2 / self._UNIT def getDerivative(self): return self._x * 2 / self._UNIT
ссылка на оригинал статьи https://habr.com/ru/post/599051/
Добавить комментарий