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