Pull to refresh

Как увидеть производную

Reading time4 min
Views14K

АПД судя по комментариям, эта статья нуждается в некоторой мотивировке. Что именно и зачем мы делаем. Коротко говоря, производную все, кто её как-то запоминает (а запоминают немногие) помнят в дальнейшем как "другой график". Это "ещё одна функция", которая описывает исходную. Мы никогда почти не интересуемся производной поточечно. А между тем производная изначально - не столько отдельная функция, сколько характеристика исходного графика в разных точках. Именно эту привязку мы и проявим в статье. КОНЕЦ АПД

ВТОРОЙ АПД о касательной как пределе секущих и другой возможной питонизации темы см. в длинном комментарии под статьёй вот тут: 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
Tags:
Hubs:
-16
Comments65

Articles