function p = tcdf_scalar(x, v, outType)
% TCDF Student's T cumulative distribution function for one element, optimised for GPU.

%   Copyright 2019 The MathWorks, Inc.

% Deal with special cases for a single element

normcutoff = 1e7;

if isnan(x) || ~(0<v)
    % NaN cases
    p = NaN("like", outType);
    
elseif x == 0
    % Make the result exact for the median.
    p = 0.5*ones("like", outType);
    
elseif (v == 1)
    % Special case for Cauchy distribution.  See Devroye pages 29 and 450.
    % Note that instead of the usual Cauchy formula (atan x)/pi + 0.5,
    % we use acot(-x), which is equivalent and avoids roundoff error.
    p = (x>0) + acot(-x)/pi;
    
elseif (v > normcutoff)
    % Normal Approximation for very large nu.
    p = 0.5 * erfc(-x ./ sqrt(2)); % normcdf(x)
    
else
    % General case: first compute F(-|x|) < .5, the lower tail.
    %
    % See Abramowitz and Stegun, formulas and 26.7.1/26.5.27 and 26.5.2
    xsq = x^2;
    if v < xsq
        % For small v, form v/(v+x^2) to maintain precision
        p = betainc(v ./ (v + xsq), v/2, 0.5, 'lower') / 2;
    else
        % For large v, form x^2/(v+x^2) to maintain precision
        p = betainc(xsq ./ (v + xsq), 0.5, v/2, 'upper') / 2;
    end
    
    % For x > 0, F(x) = 1 - F(-|x|).
    if (x > 0)
        p = 1 - p; % p < .5, cancellation not a problem
    end
    
end

end