2
$\begingroup$

If I define

f[x_?NumericQ] := (Sow[x]; SawtoothWave[x])
D[f[x], x] /. x -> 1.1
(* 5.29432 *)

numeric differentiation fails, despite the function being smooth and well-defined in a region around 1.1.

We can see the values of x at which f is evaluated

Reap[D[f[x], x] /. x -> 1.1]
(* {5.29432, {{1.1, 1.15263, 1.20526, 1.25789, 1.31053, 1.36316, 1.41579,
    1.46842, 1.52105, 1.04737, 0.994737, 0.942105, 0.889474, 0.836842,
    0.784211, 0.731579, 0.678947}}} *)

Mathematica provides ND for numerical differentiation, which behaves sensibly

Needs["NumericalCalculus`"]
Reap[ND[f[x], x, 1.1, Scale -> 0.01]]
(* {1., {{1.1, 1.11, 1.105, 1.1025, 1.10125, 1.10063, 1.10031, 1.10016}}} *)

The documentation for D does not provide obvious clues on what is to be expected with numeric arguments.

The sensible advice is not to use D with numeric functions. However, it may not always be obvious to the user that D will be applied to an expression.

Related question Derivative of mod gives unacceptable results

$\endgroup$
  • 2
    $\begingroup$ D[f[x],x] gets turned into Derivative[1][f][x] (f'), so this is really a question of how Derivative behaves for numerical functions. You can investigate what's happening with: f[x_?NumericQ] := (Echo[{x, SawtoothWave[x]}]; SawtoothWave[x]); D[f[x], x] /. x -> 1.1. It seems to naively sample some points with distance O(1), and then generate a result. $\endgroup$ – QuantumDot Aug 29 '16 at 11:26
  • 1
    $\begingroup$ SawtoothWave'[1.1] returns 1 $\endgroup$ – Bob Hanlon Aug 29 '16 at 12:39
  • 2
    $\begingroup$ Somewhere on this site someone discusses the numerical method used by Derivative, which, as I recall, is slightly different from ND. It could be discussed as a side-issue in a Q&A about something else, but for whatever reason, I can't locate it... $\endgroup$ – Michael E2 Aug 29 '16 at 13:05
  • 5
    $\begingroup$ I think this is the one I was thinking of: (29329) --The question is somewhat different, but @acl's answer shows that the eighth-order central difference is being used to numerically compute the derivative. That seems to be true here, too. $\endgroup$ – Michael E2 Aug 30 '16 at 0:58
4
$\begingroup$

Here is a partial explanation

f[x_?NumericQ] := (Sow[x]; SawtoothWave[x])

Collecting 'x' and 'f[x]' and defining an interpolation function of the maximum supported order

data = {#, f[#]} & /@ Flatten[Last[Reap[D[f[x], x] /. x -> 1.1]]]
(* {{1.1, 0.1}, {1.15263, 0.152632}, {1.20526, 0.205263}, {1.25789, 
  0.257895}, {1.31053, 0.310526}, {1.36316, 0.363158}, {1.41579, 
  0.415789}, {1.46842, 0.468421}, {1.52105, 0.521053}, {1.04737, 
  0.0473684}, {0.994737, 0.994737}, {0.942105, 0.942105}, {0.889474, 
  0.889474}, {0.836842, 0.836842}, {0.784211, 0.784211}, {0.731579, 
  0.731579}, {0.678947, 0.678947}} *)

intdata = Interpolation[data, InterpolationOrder -> 16];

The interpolating function passes through the points, but the order is much too high to give a useful result here.

    Show[{ListPlot[data], Plot[intdata[t], {t, 0.8, 1.4}]}, PlotRange -> {-1, 2}]

enter image description here

We have a match to the value returned by D.

{intdata'[1.1], D[f[x], x] /. x -> 1.1}
(* {5.29432, 5.29432} *)

This doesn't explain the sample values chosen, those these are obviously equally spaced.

EDIT

It seems that the sample values have a spacing of 1/19, independent of where the derivative is evaluated.

$\endgroup$

Not the answer you're looking for? Browse other questions tagged or ask your own question.