# Good Practice in Defining Numeric Functions

I would like to define numeric functions for Mathematica such that they behave 'nicely' in much the same way as the built-in numeric functions do. For example, consider the following numerical function from Mathematica:

HypergeometricPFQ[{1/2, 1/3}, {1/4, 1/5}, x]
HypergeometricPFQ[{1/2, 1/3}, {1/4, 1/5}, 1]
HypergeometricPFQ[{1/2, 1/3}, {1/4, 1/5}, 1.0]


The first two return a 'nice' output that is symbolic while the last one returns a number. Furthermore, the 2nd one above can be used numerically but only becomes a floating point if it is combined with another imprecise number (that is, if I multiply it by Pi it remains symbolic, while multiplying by 3.14 returns a number). Furthermore, NumericQ returns True for the latter two.

How do I replicate such behaviour in my own definitions of numerical functions? Take for example:

f[x_] := NIntegrate[t^(t-x), {t, 1, x}]


## 2 Answers

You mainly need NumericFunction attribute. You may also need Listable attribute that many numeric functions own:

ClearAll@f
SetAttributes[f, {NumericFunction, Listable}]
f[x_ /; Precision[x] != Infinity] :=
NIntegrate[t^(t - x), {t, 1, x}, WorkingPrecision -> Precision@x]

f[{x, 2, 2.}]
(* {f[x], f[2], 0.874227} *)

f[x] // NumericQ
(* False *)

f[2] // NumericQ
(* True *)

f[2.] // NumericQ
(* True *)

f[2] + 1.
(* 1.87423 *)

N[f[2], 16]
(* 0.8742270873919437 *)

• Can you expand your answer on defining numeric functions when they have multiple variables? Adding ?InexactNumberQ to each argument does not work as it requires all arguments to be inexact (as opposed to any one of them). I'm guessing a /; condition would work, but I'm unsure if there's a nicer way. Sep 13, 2020 at 8:31
• @JP-Ellis Hint: try Precision[{1, 216}] and observe the output. If you still feel confused, I can add an example :) . Sep 13, 2020 at 9:11
• Fair enough. I was thinking of using InexactNumberQ as it is equivalent to Precision[x] != Infinity, but does not work as nicely with multiple arguments. Thanks! Sep 13, 2020 at 9:13
?NumericFunction


give a definition for Mathematica for NumericFunction. There is the documentation page for NumericFunction. And there is the great input:

list=Select[Names["System*"], MemberQ[Attributes[#], NumericFunction] &];

MemberQ[list, HypergeometricPFQ_]


(True)

The definition is:

"NumericFunction is an attribute that can be assigned to a symbol f to indicate that f[Subscript[arg, 1],Subscript[arg, 2],[Ellipsis]] should be considered a numeric quantity whenever all the Subscript[arg, i] are numeric quantities. "

The input for defining a function in Mathematica is

SetAttributes[f, NumericFunction]


This generates no output explicit.

The condition for a confirmation is easily matched, all arguments have to be numeric and the the output of the function has to be numeric. With the explicit definition above that is already matched if the arguments are numeric.

f[2 + 3 I] // Numeric


(* True *)

This is rather short compared for example for the effort to define a Function. Important is that NumeriQ is independent of the body in Wolfram Language definition. It depends on the input arguments and the output. NumericQ is only valid so far for scalars.

F[x_, y_] := {x + y, x - y}
F[5, 6] // NumericQ


(* False *)

On the documentation page for NumberQ there is a table in the section Properties and Relations that offers some ideas for tests with NumericQ and defines the check to do for the arguments.

TableForm[
Table[{x, NumberQ[x],
MatchQ[#, _Integer | _Rational | _Real | _Complex] &[x],
NumericQ[x]}, {x, {1, 3/2, 1.5, 1 + I, E, Sin[1],
HypergeometricPFQ[{1/2, 1/3}, {1/4, 1/5}, y],
HypergeometricPFQ[{1/2, 1/3}, {1/4, 1/5}, 1],
HypergeometricPFQ[{1/2, 1/3}, {1/4, 1/5}, 1.0], Underflow[],
Overflow[], Abs[-1 + I], RealAbs[-1], Arg[-1 - I], f[1], f[I],
f[Sin[0]], F[2, 3], F[I, -I], Infinity}}],
TableHeadings -> {{}, {"x", "NumberQ", "MatchQ", "NumericQ"}}]


So there is a vast collection of functions that is in need to be known how it is implemented in Mathematica and Wolfram Language

There is an easy rule:

If NumberQ[x] is True, then NumericQ[x] is also True.

Mathematica/Wolfram Language has the InexactNumberQ that will extend the table with more columns and rows.

An impressive perspective on how does a function in Mathematica/Wolfram Language not behave 'nicely'?

InexactNumberQ, Not[MachineNumberQ], ListQ, StringQ, MatrixQ, ArrayQ, VectorQ, AssociationQ and others. Mathematica/WL knows Dimensions, Colors, Graphs, Intervals and more.

Names["*Q"]


A different perspective is

Names["*Function"]


to create functions that do not well behave for NumericQ.

For most really needed that compilation Compile does not alter the attribute NumericFunction.

For investigation the built-in Attributes. This how-to-restore-function-attributes-to-default shows how to deal with the combination of function attributes. This is extended in the built-in Protected documentation page.