1#
2# CDDL HEADER START
3#
4# The contents of this file are subject to the terms of the
5# Common Development and Distribution License (the "License").
6# You may not use this file except in compliance with the License.
7#
8# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9# or http://www.opensolaris.org/os/licensing.
10# See the License for the specific language governing permissions
11# and limitations under the License.
12#
13# When distributing Covered Code, include this CDDL HEADER in each
14# file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15# If applicable, add the following below this CDDL HEADER, with the
16# fields enclosed by brackets "[]" replaced with your own identifying
17# information: Portions Copyright [yyyy] [name of copyright owner]
18#
19# CDDL HEADER END
20#
21
22#
23# Copyright (c) 2009, 2010, Oracle and/or its affiliates. All rights reserved.
24#
25
26#
27# This test checks whether arithmetric math correctly
28# converts a IEEE 754-2008 floating-point value to the C99 hexfloat format
29# and back _without_ using digits.
30#
31# This was reported as CR #6855875 ("typeset -X x ; print $x # does not
32# print sufficient digits to restore value"):
33# ------------ snip ------------
34# $ typeset -X varname # was added to ksh93 to get a reliable way
35# (using the C99 "hexfloat" format (see printf(3c)'s "%a" format)) to
36# serialise a IEEE754-2008 floating-point value to a string and later feed
37# it back into a application _without_ loosing any precision (normal
38# base10 floating-point values (e.g. used by $ typeset -E/-F-G #) cause
39# rounding errors since IEEE754-2008 |long double| uses base2).
40# However $ typeset -l -X x ; ... ; print $x # currently does not print
41# sufficient number of digits to restore the full |long double| value as
42# expected, instead some digits are missing, resulting in an unwanted
43# rounding.
44# Example:
45# -- snip --
46# $ ksh93 -c 'typeset -l -X y y_ascii; (( y=sin(90) )) ; y_ascii=$y ; (( y
47# == y_ascii )) || print "no match,\n\t$(printf "%a\n" y)\n!=\n\t$(printf
48# "%a\n" y_ascii)"'
49# no match,
50#         0x1.c9b9ee41cb8665c7890a136ace6bp-01
51# !=
52#         0x1.c9b9ee41cc000000000000000000p-01
53# -- snip --
54# Frequency
55#    Always
56# Regression
57#    No
58# Steps to Reproduce
59#    [See description]
60# Expected Result
61#    [See description]
62# Actual Result
63#    [See description]
64# Error Message(s)
65#    -
66# Test Case
67#    typeset -l -X y y_ascii
68# (( y=sin(90) ))
69# y_ascii=$y # convert y to string and store it in "y_ascii"
70# if (( y == y_ascii )) ; then
71#     print "no match,\n\t$(printf "%a\n" y)\n!=\n\t$(printf "%a\n"
72# y_ascii)"
73# fi
74# Workaround
75#    1. Manually increase the number of digits via typeset
76# -X<numdigits>
77#     OR
78# 2. Use $ printf "%a" varname #
79# ------------ snip ------------
80#
81
82# test setup
83function err_exit
84{
85	print -u2 -n "\t"
86	print -u2 -r ${Command}[$1]: "${@:2}"
87	(( Errors < 127 && Errors++ ))
88}
89alias err_exit='err_exit $LINENO'
90
91set -o nounset
92Command=${0##*/}
93integer Errors=0
94
95
96# declare variables
97typeset		str
98integer		i
99float		x
100float -a	test_values
101
102typeset -l -X	y # hexfloat
103typeset -l -E	y_restored1
104typeset -l -F	y_restored2
105typeset -l -X	y_restored3
106
107
108# create array of test values
109for (( x=-181. ; x < 361. ; x+=.1 )) ; do
110	test_values+=( x )
111done
112test_values+=( 0 -0 +0 ) # (nan -nan inf -inf) are excluded since nan!=nan is always "true"
113
114
115# run the tests
116for (( i=0 ; i < ${#test_values[@]} ; i++ )) ; do
117	(( y=sin(test_values[i]) ))
118
119	# convert floating-point value to string (using the hexfloat format) and store it in "str"
120	str="${y}"
121
122	# convert it back (via string assignment)
123	y_restored1="${str}"
124	y_restored2="${str}"
125	y_restored3="${str}"
126	(( y == y_restored1 )) || err_exit "no match,"$'\n\t'"$(printf "%a\n" y)"$'\n'"!="$'\n\t'"$(printf "%a\n" y_restored1)"
127	(( y == y_restored2 )) || err_exit "no match,"$'\n\t'"$(printf "%a\n" y)"$'\n'"!="$'\n\t'"$(printf "%a\n" y_restored2)"
128	(( y == y_restored3 )) || err_exit "no match,"$'\n\t'"$(printf "%a\n" y)"$'\n'"!="$'\n\t'"$(printf "%a\n" y_restored3)"
129
130	# convert it back (using arithmetric expression)
131	(( y_restored1=str ))
132	(( y_restored2=str ))
133	(( y_restored3=str ))
134	(( y == y_restored1 )) || err_exit "no match,"$'\n\t'"$(printf "%a\n" y)"$'\n'"!="$'\n\t'"$(printf "%a\n" y_restored1)"
135	(( y == y_restored2 )) || err_exit "no match,"$'\n\t'"$(printf "%a\n" y)"$'\n'"!="$'\n\t'"$(printf "%a\n" y_restored2)"
136	(( y == y_restored3 )) || err_exit "no match,"$'\n\t'"$(printf "%a\n" y)"$'\n'"!="$'\n\t'"$(printf "%a\n" y_restored3)"
137
138	# we exit if we get more than 8 errors (126 would be the maximum)
139	(( Errors > 8 )) && exit $((Errors))
140done
141
142
143# tests done
144exit $((Errors))
145