Repository navigation
Expand file tree
/
Copy pathBlockConvert.m
More file actions
90 lines (78 loc) · 2.82 KB
/
Copy pathBlockConvert.m
File metadata and controls
90 lines (78 loc) · 2.82 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
function result = BlockConvert(V, MX)
% BLOCKCONVERT Converts a single block vector to OCP MX format.
%
% RESULT = BLOCKCONVERT(V, MX) converts the input vector V to MX
% format using the configuration specified in MX. The conversion
% follows the algorithm specified in Section 6.3 of the OCP MX
% specification. The shared scale factor X is set to the largest
% power of two less than or equal to the maximum absolute value in
% V, divided by the largest power of two representable in the element
% format. The elements are then divided by X and rounded to the
% element format specified by MX.element_opts.
%
% V must be a numeric vector of length MX.k. If V contains NaN values,
% the shared scale is computed from the non-NaN elements. NaN positions
% are preserved in the output vector. If all elements are NaN,
% RESULT.scale is set to NaN and RESULT.vector is set to a vector of NaNs.
%
% For the E4M3 format, the maximum representable value is corrected
% to 448 as specified by OCP, overriding the value of 480 computed
% by CPFloat. If saturation is enabled, values exceeding 448 are
% clamped. If saturation is disabled, values between 448 and 480
% are mapped to infinity.
%
% RESULT is a structure with fields:
% RESULT.scale - shared scale factor X.
% RESULT.vector - vector of private elements of length MX.k.
%
arguments
V {mustBeNumeric}
MX = struct()
end
MX = merge_MX(MX);
V= V(:);
% Handle zero vector.
if all(V == 0)
result.scale = 1;
result.vector = zeros(size(V));
return
end
% if any nans or infinities are present, scale and vector all become nan
if any(isnan(V)) || any(isinf(V))
result.scale = NaN;
result.vector = NaN(size(V));
return
end
%Set X to largest power of 2 less than maximum value in vector
[max_val, ~] = max(abs((V)));
E = floor(log2(max_val));
%Divide by largest power of 2 in element datatype
[~, opts] = cpfloat(pi, MX.element_opts);
emax = opts.params(3);
u = 2^-opts.params(1);
E = (E-emax) + MX.expAdj;
% Clamp exponent to the representable range of the scale
max_exponent = 2^(MX.scale_bits - 1) - 1;
min_exponent = -max_exponent;
E = min(max(E, min_exponent), max_exponent);
%Set scale factor
X = 2^E;
%Divide all elements by the scale factor
P = V / X ;
% Manually handle OCP-correct maxVal for E4M3.
if strcmpi(MX.element_opts.format, 'E4M3')
nanPos = isnan(P);
if MX.element_opts.saturation
% Clamp to OCP max of 448.
P = max(-448, min(448, P));
else
% Values between 448 and 480 should overflow to NaN.
P(P > 448) = NaN;
P(P < -448) = NaN;
end
P(nanPos) = NaN; % Restore NaN positions
end
% Convert number of bits being used
result.scale = X;
result.vector = cpfloat(P, MX.element_opts);
end