mirror of
https://github.com/Unidata/netcdf-c.git
synced 2024-11-27 07:30:33 +08:00
Merge pull request #2130 from nco/csz_gbg
Granular BitGroom feature for netcdf-c
This commit is contained in:
commit
3980d7616a
@ -329,11 +329,13 @@ there. */
|
||||
#define NC_MAX_DEFLATE_LEVEL 9 /**< Maximum deflate level. */
|
||||
|
||||
#define NC_NOQUANTIZE 0 /**< No quantization in use. */
|
||||
#define NC_QUANTIZE_BITGROOM 1 /**< Use bitgroom quantization. */
|
||||
#define NC_QUANTIZE_BITGROOM 1 /**< Use BitGroom quantization. */
|
||||
#define NC_QUANTIZE_GRANULARBG 2 /**< Use Granular BitGroom quantization. */
|
||||
|
||||
/** When quantization is used for a variable, an attribute of this
|
||||
* name is added. */
|
||||
#define NC_QUANTIZE_ATT_NAME "_QuantizeBitgroomNumberOfSignificantDigits"
|
||||
/** When quantization is used for a variable, an attribute of the
|
||||
* appropriate name is added. */
|
||||
#define NC_QUANTIZE_BITGROOM_ATT_NAME "_QuantizeBitgroomNumberOfSignificantDigits"
|
||||
#define NC_QUANTIZE_GRANULARBG_ATT_NAME "_QuantizeGranularBitGroomNumberOfSignificantDigits"
|
||||
|
||||
/** For quantization, the allowed value of number of significant
|
||||
* digits for float. */
|
||||
|
@ -63,6 +63,6 @@
|
||||
#define NC_HAS_NCZARR @NC_HAS_NCZARR@ /*!< Parallel I/O with filter support. */
|
||||
#define NC_HAS_MULTIFILTERS @NC_HAS_MULTIFILTERS@ /*!< Nczarr support. */
|
||||
#define NC_HAS_LOGGING @NC_HAS_LOGGING@ /*!< Logging support. */
|
||||
#define NC_HAS_QUANTIZE @NC_HAS_QUANTIZE@
|
||||
#define NC_HAS_QUANTIZE @NC_HAS_QUANTIZE@ /*!< Quantization support. */
|
||||
|
||||
#endif
|
||||
|
@ -467,18 +467,19 @@ nc_def_var_deflate(int ncid, int varid, int shuffle, int deflate, int deflate_le
|
||||
/**
|
||||
Turn on quantization for a variable.
|
||||
|
||||
The data data are quantized by setting unneeded bits alternately to
|
||||
1/0, so that they may compress well. Quantization is lossy (data
|
||||
are irretrievably altered), and it improves the compression ratio
|
||||
provided by a subsequent lossless compression filter. Quantization
|
||||
alone will not reduce the size of the data - lossless compression
|
||||
like zlib must also be used (see nc_def_var_deflate()).
|
||||
The data are quantized by setting unneeded bits to zeros or ones
|
||||
so that they may compress well. BitGroom sets bits alternately to 1/0,
|
||||
while Granular BitGroom (GBG) sets (more) bits to zeros.
|
||||
Quantization is lossy (data are irretrievably altered), and it
|
||||
improves the compression ratio provided by a subsequent lossless
|
||||
compression filter. Quantization alone will not reduce the data size.
|
||||
Lossless compression like zlib must also be used (see nc_def_var_deflate()).
|
||||
|
||||
Producers of large datasets may find that using quantize with
|
||||
compression will result in significant improvent in the final data
|
||||
size.
|
||||
|
||||
This data quantization used the bitgroom algorithm. A notable
|
||||
This data quantization used the BitGroom algorithm. A notable
|
||||
feature of BitGroom is that the data it processes remain in IEEE754
|
||||
format after quantization. Therefore the BitGroom algorithm does
|
||||
nothing when data are read.
|
||||
@ -487,7 +488,7 @@ nc_def_var_deflate(int ncid, int varid, int shuffle, int deflate, int deflate_le
|
||||
NC_DOUBLE. Attempts to set quantization for other variable
|
||||
types return an error (NC_EINVAL).
|
||||
|
||||
Variables which use quantize will have added an attribute with name
|
||||
Variables that use quantize will have added an attribute with name
|
||||
::NC_QUANTIZE_ATT_NAME, which will contain the number of
|
||||
significant digits. Users should not delete or change this
|
||||
attribute. This is the only record that quantize has been applied
|
||||
@ -500,10 +501,10 @@ nc_def_var_deflate(int ncid, int varid, int shuffle, int deflate, int deflate_le
|
||||
|
||||
Quantization may be applied to scalar variables.
|
||||
|
||||
When type conversion takes place during a write, the it occurs
|
||||
When type conversion takes place during a write, then it occurs
|
||||
before quantization is applied. For example, if nc_put_var_double()
|
||||
is called on a variable of type NC_FLOAT, which has quantizze
|
||||
turned on, then the data are first converted from dounle to float,
|
||||
is called on a variable of type NC_FLOAT, which has quantize
|
||||
turned on, then the data are first converted from double to float,
|
||||
then quantization is applied to the float values.
|
||||
|
||||
As with the deflate settings, quantize settings may only be
|
||||
@ -516,7 +517,7 @@ nc_def_var_deflate(int ncid, int varid, int shuffle, int deflate, int deflate_le
|
||||
variable which has been quantized is readable to older versions of
|
||||
the netCDF libraries, and to netCDF-Java.
|
||||
|
||||
For more information about quantization and the bitgroom filter, see
|
||||
For more information about quantization and the BitGroom filter, see
|
||||
|
||||
Zender, C. S. (2016), Bit Grooming: Statistically accurate
|
||||
precision-preserving quantization with compression, evaluated in
|
||||
@ -528,7 +529,7 @@ nc_def_var_deflate(int ncid, int varid, int shuffle, int deflate, int deflate_le
|
||||
@param ncid File ID.
|
||||
@param varid Variable ID. ::NC_GLOBAL may not be used.
|
||||
@param quantize_mode Quantization mode. May be ::NC_NOQUANTIZE or
|
||||
::NC_QUANTIZE_BITGROOM.
|
||||
::NC_QUANTIZE_BITGROOM or ::NC_QUANTIZE_GRANULARBG.
|
||||
@param nsd Number of significant digits. May be any integer from 1
|
||||
to ::NC_QUANTIZE_MAX_FLOAT_NSD (for variables of type ::NC_FLOAT)
|
||||
or ::NC_QUANTIZE_MAX_DOUBLE_NSD (for variables of type
|
||||
|
@ -528,15 +528,15 @@ nc_inq_var_fill(int ncid, int varid, int *no_fill, void *fill_valuep)
|
||||
}
|
||||
|
||||
/** @ingroup variables
|
||||
* Learn whether BitGroom quantization is on for a variable, and, if so,
|
||||
* Learn whether quantization is on for a variable, and, if so,
|
||||
* the NSD setting.
|
||||
*
|
||||
* @param ncid File ID.
|
||||
* @param varid Variable ID. Must not be NC_GLOBAL.
|
||||
* @param quantize_modep Pointer that gets a 0 if BitGroom is not in
|
||||
* @param quantize_modep Pointer that gets a 0 if quantization is not in
|
||||
* use for this var, and a 1 if it is. Ignored if NULL.
|
||||
* @param nsdp Pointer that gets the NSD setting (from 1 to 15), if
|
||||
* BitGroom is in use. Ignored if NULL.
|
||||
* quantization is in use. Ignored if NULL.
|
||||
*
|
||||
* @return 0 for success, error code otherwise.
|
||||
* @author Charlie Zender, Ed Hartnett
|
||||
|
@ -1202,13 +1202,24 @@ static int get_quantize_info(NC_VAR_INFO_T *var)
|
||||
/* Try to open an attribute of the correct name for quantize
|
||||
* info. */
|
||||
datasetid = ((NC_HDF5_VAR_INFO_T *)var->format_var_info)->hdf_datasetid;
|
||||
attid = H5Aopen_by_name(datasetid, ".", NC_QUANTIZE_ATT_NAME,
|
||||
attid = H5Aopen_by_name(datasetid, ".", NC_QUANTIZE_BITGROOM_ATT_NAME,
|
||||
H5P_DEFAULT, H5P_DEFAULT);
|
||||
|
||||
if (attid > 0)
|
||||
{
|
||||
var->quantize_mode = NC_QUANTIZE_BITGROOM;
|
||||
}
|
||||
else
|
||||
{
|
||||
attid = H5Aopen_by_name(datasetid, ".", NC_QUANTIZE_GRANULARBG_ATT_NAME,
|
||||
H5P_DEFAULT, H5P_DEFAULT);
|
||||
if (attid > 0)
|
||||
var->quantize_mode = NC_QUANTIZE_GRANULARBG;
|
||||
}
|
||||
|
||||
/* If there is an attribute, read it for the nsd. */
|
||||
if (attid > 0)
|
||||
{
|
||||
var->quantize_mode = NC_QUANTIZE_BITGROOM;
|
||||
if (H5Aread(attid, H5T_NATIVE_INT, &var->nsd) < 0)
|
||||
return NC_EHDFERR;
|
||||
if (H5Aclose(attid) < 0)
|
||||
|
@ -721,10 +721,11 @@ nc_def_var_extra(int ncid, int varid, int *shuffle, int *unused1,
|
||||
{
|
||||
/* Only two valid mode settings. */
|
||||
if (*quantize_mode != NC_NOQUANTIZE &&
|
||||
*quantize_mode != NC_QUANTIZE_BITGROOM)
|
||||
*quantize_mode != NC_QUANTIZE_BITGROOM &&
|
||||
*quantize_mode != NC_QUANTIZE_GRANULARBG)
|
||||
return NC_EINVAL;
|
||||
|
||||
if (*quantize_mode == NC_QUANTIZE_BITGROOM)
|
||||
if (*quantize_mode == NC_QUANTIZE_BITGROOM || *quantize_mode == NC_QUANTIZE_GRANULARBG)
|
||||
{
|
||||
/* Only float and double types can have quantization. */
|
||||
if (var->type_info->hdr.id != NC_FLOAT &&
|
||||
@ -806,22 +807,24 @@ done:
|
||||
* error.)
|
||||
*
|
||||
* When quantize is turned on, and the number of significant digits
|
||||
* has been specified, then the netCDF library will apply all zeros or
|
||||
* has been specified, then the netCDF library will quantize according
|
||||
* to the selected algorithm. BitGroom will apply all zeros or
|
||||
* all ones (alternating) to bits which are not needed to specify the
|
||||
* value to the number of significant digits. This will change the
|
||||
* value of the data, but will make it more compressable.
|
||||
* value to the number of significant digits. GranularBG will zero
|
||||
* more bits than BG, and thus be more compressible and less accurate.
|
||||
* Both will change the value of the data, and will make it more compressible.
|
||||
*
|
||||
* Quantizing the data does not reduce the size of the data on disk,
|
||||
* but combining quantize with compression will allow for better
|
||||
* compression. Since the data values are changed, the use of quantize
|
||||
* and compression such as deflate constitute lossy compression.
|
||||
* and compression such as DEFLATE constitute lossy compression.
|
||||
*
|
||||
* Producers of large datasets may find that using quantize with
|
||||
* compression will result in significant improvent in the final data
|
||||
* size.
|
||||
*
|
||||
* Variables which use quantize will have added an attribute with name
|
||||
* ::NC_QUANTIZE_ATT_NAME, which will contain the number of
|
||||
* ::NC_QUANTIZE_[ALG_NAME]_ATT_NAME, which will contain the number of
|
||||
* significant digits. Users should not delete or change this
|
||||
* attribute. This is the only record that quantize has been applied
|
||||
* to the data.
|
||||
@ -839,7 +842,7 @@ done:
|
||||
* @param ncid File ID.
|
||||
* @param varid Variable ID. NC_GLOBAL may not be used.
|
||||
* @param quantize_mode Quantization mode. May be ::NC_NOQUANTIZE or
|
||||
* ::NC_QUANTIZE_BITGROOM.
|
||||
* ::NC_QUANTIZE_BITGROOM or ::NC_QUANTIZE_GRANULARBG.
|
||||
* @param nsd Number of significant digits. May be any integer from 1
|
||||
* to ::NC_QUANTIZE_MAX_FLOAT_NSD (for variables of type ::NC_FLOAT) or
|
||||
* ::NC_QUANTIZE_MAX_DOUBLE_NSD (for variables of type ::NC_DOUBLE).
|
||||
|
@ -1022,7 +1022,12 @@ var_create_dataset(NC_GRP_INFO_T *grp, NC_VAR_INFO_T *var, nc_bool_t write_dimid
|
||||
/* If quantization is in use, write an attribute indicating it, a
|
||||
* single integer which is the number of significant digits. */
|
||||
if (var->quantize_mode == NC_QUANTIZE_BITGROOM)
|
||||
if ((retval = nc4_put_att(var->container, var->hdr.id, NC_QUANTIZE_ATT_NAME, NC_INT, 1,
|
||||
if ((retval = nc4_put_att(var->container, var->hdr.id, NC_QUANTIZE_BITGROOM_ATT_NAME, NC_INT, 1,
|
||||
&var->nsd, NC_INT, 0)))
|
||||
BAIL(retval);
|
||||
|
||||
if (var->quantize_mode == NC_QUANTIZE_GRANULARBG)
|
||||
if ((retval = nc4_put_att(var->container, var->hdr.id, NC_QUANTIZE_GRANULARBG_ATT_NAME, NC_INT, 1,
|
||||
&var->nsd, NC_INT, 0)))
|
||||
BAIL(retval);
|
||||
|
||||
|
142
libsrc4/nc4var.c
142
libsrc4/nc4var.c
@ -511,9 +511,10 @@ NC4_var_par_access(int ncid, int varid, int par_access)
|
||||
* @param fill_value The fill value.
|
||||
* @param strict_nc3 Non-zero if strict model in effect.
|
||||
* @param quantize_mode May be ::NC_NOQUANTIZE or
|
||||
* ::NC_QUANTIZE_BITGROOM.
|
||||
* ::NC_QUANTIZE_BITGROOM or ::NC_QUANTIZE_GRANULARBG.
|
||||
* @param nsd Number of significant diggits for quantizize. Ignored
|
||||
* unless quantize_mode is ::NC_QUANTIZE_BITGROOM.
|
||||
* unless quantize_mode is ::NC_QUANTIZE_BITGROOM or
|
||||
* ::NC_QUANTIZE_GRANULARBG.
|
||||
*
|
||||
* @returns ::NC_NOERR No error.
|
||||
* @returns ::NC_EBADTYPE Type not found.
|
||||
@ -526,17 +527,27 @@ nc4_convert_type(const void *src, void *dest, const nc_type src_type,
|
||||
int nsd)
|
||||
{
|
||||
/* These vars are used with quantize feature. */
|
||||
const double bit_per_dcm_dgt_prc = M_LN10 / M_LN2; /* 3.32 [frc] Bits per decimal digit of precision */
|
||||
const double bit_per_dgt = M_LN10 / M_LN2; /* 3.32 [frc] Bits per decimal digit of precision = log2(10) */
|
||||
const double dgt_per_bit= M_LN2 / M_LN10; /* 0.301 [frc] Decimal digits per bit of precision = log10(2) */
|
||||
double mnt; /* [frc] Mantissa, 0.5 <= mnt < 1.0 */
|
||||
double mnt_fabs; /* [frc] fabs(mantissa) */
|
||||
double mnt_log10_fabs; /* [frc] log10(fabs(mantissa))) */
|
||||
double val; /* [frc] Copy of input value to avoid indirection */
|
||||
double mss_val_cmp_dbl; /* Missing value for comparison to double precision values */
|
||||
float mss_val_cmp_flt; /* Missing value for comparison to single precision values */
|
||||
int bit_xpl_nbr_zro; /* [nbr] Number of explicit bits to zero */
|
||||
int dgt_nbr; /* [nbr] Number of digits before decimal point */
|
||||
int qnt_pwr; /* [nbr] Power of two in quantization mask: qnt_msk = 2^qnt_pwr */
|
||||
int xpn_bs2; /* [nbr] Binary exponent xpn_bs2 in val = sign(val) * 2^xpn_bs2 * mnt, 0.5 < mnt <= 1.0 */
|
||||
size_t idx;
|
||||
unsigned int *u32_ptr;
|
||||
unsigned int msk_f32_u32_zro;
|
||||
unsigned int msk_f32_u32_one;
|
||||
unsigned int msk_f32_u32_hshv;
|
||||
unsigned long long int *u64_ptr;
|
||||
unsigned long long int msk_f64_u64_zro;
|
||||
unsigned long long int msk_f64_u64_one;
|
||||
unsigned long long int msk_f64_u64_hshv;
|
||||
unsigned short prc_bnr_xpl_rqr; /* [nbr] Explicitly represented binary digits required to retain */
|
||||
ptr_unn op1; /* I/O [frc] Values to quantize */
|
||||
|
||||
@ -559,19 +570,11 @@ nc4_convert_type(const void *src, void *dest, const nc_type src_type,
|
||||
|
||||
/* If quantize is in use, set up some values. Quantize can only be
|
||||
* used when the destination type is NC_FLOAT or NC_DOUBLE. */
|
||||
if (quantize_mode == NC_QUANTIZE_BITGROOM)
|
||||
if (quantize_mode != NC_NOQUANTIZE)
|
||||
{
|
||||
assert(dest_type == NC_FLOAT || dest_type == NC_DOUBLE);
|
||||
/* How many bits to preserve? Being conservative, we round up the
|
||||
* exact binary digits of precision. Add one because the first bit
|
||||
* is implicit not explicit but corner cases prevent our taking
|
||||
* advantage of this. */
|
||||
prc_bnr_xpl_rqr = (unsigned short)ceil(nsd * bit_per_dcm_dgt_prc) + 1;
|
||||
if (dest_type == NC_DOUBLE)
|
||||
prc_bnr_xpl_rqr++; /* Seems necessary for double-precision
|
||||
* ppc=array(1.234567,1.0e-6,$dmn) */
|
||||
|
||||
/* Determine masks, copy the data, do the quantization. */
|
||||
/* Parameters shared by both BitGroom and GranularBG */
|
||||
if (dest_type == NC_FLOAT)
|
||||
{
|
||||
/* Determine the fill value. */
|
||||
@ -580,6 +583,34 @@ nc4_convert_type(const void *src, void *dest, const nc_type src_type,
|
||||
else
|
||||
mss_val_cmp_flt = NC_FILL_FLOAT;
|
||||
|
||||
}
|
||||
else
|
||||
{
|
||||
|
||||
/* Determine the fill value. */
|
||||
if (fill_value)
|
||||
mss_val_cmp_dbl = *(double *)fill_value;
|
||||
else
|
||||
mss_val_cmp_dbl = NC_FILL_DOUBLE;
|
||||
|
||||
}
|
||||
|
||||
/* Parameters BitGroom needs to be set once */
|
||||
if (quantize_mode == NC_QUANTIZE_BITGROOM)
|
||||
{
|
||||
|
||||
/* How many bits to preserve? Being conservative, we round up the
|
||||
* exact binary digits of precision. Add one because the first bit
|
||||
* is implicit not explicit but corner cases prevent our taking
|
||||
* advantage of this. */
|
||||
prc_bnr_xpl_rqr = (unsigned short)ceil(nsd * bit_per_dgt) + 1;
|
||||
if (dest_type == NC_DOUBLE)
|
||||
prc_bnr_xpl_rqr++; /* Seems necessary for double-precision
|
||||
* ppc=array(1.234567,1.0e-6,$dmn) */
|
||||
|
||||
if (dest_type == NC_FLOAT)
|
||||
{
|
||||
|
||||
bit_xpl_nbr_zro = BIT_XPL_NBR_SGN_FLT - prc_bnr_xpl_rqr;
|
||||
|
||||
/* Create mask */
|
||||
@ -596,13 +627,8 @@ nc4_convert_type(const void *src, void *dest, const nc_type src_type,
|
||||
}
|
||||
else
|
||||
{
|
||||
bit_xpl_nbr_zro = BIT_XPL_NBR_SGN_DBL - prc_bnr_xpl_rqr;
|
||||
assert(bit_xpl_nbr_zro <= BIT_XPL_NBR_SGN_DBL - NCO_PPC_BIT_XPL_NBR_MIN);
|
||||
if (fill_value)
|
||||
mss_val_cmp_dbl = *(double *)fill_value;
|
||||
else
|
||||
mss_val_cmp_dbl = NC_FILL_DOUBLE;
|
||||
|
||||
bit_xpl_nbr_zro = BIT_XPL_NBR_SGN_DBL - prc_bnr_xpl_rqr;
|
||||
/* Create mask. */
|
||||
msk_f64_u64_zro = 0ul; /* Zero all bits. */
|
||||
msk_f64_u64_zro = ~msk_f64_u64_zro; /* Turn all bits to ones. */
|
||||
@ -614,7 +640,11 @@ nc4_convert_type(const void *src, void *dest, const nc_type src_type,
|
||||
/* Bit Set mask for OR: Put ones into bits to be set, zeros in
|
||||
* untouched bits. */
|
||||
msk_f64_u64_one =~ msk_f64_u64_zro;
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
} /* endif quantize */
|
||||
|
||||
/* OK, this is ugly. If you can think of anything better, I'm open
|
||||
@ -1401,7 +1431,79 @@ nc4_convert_type(const void *src, void *dest, const nc_type src_type,
|
||||
if (op1.dp[idx] != mss_val_cmp_dbl && u64_ptr[idx] != 0ULL) /* Never quantize upwards floating point values of zero */
|
||||
u64_ptr[idx] |= msk_f64_u64_one;
|
||||
}
|
||||
} /* endif quantize */
|
||||
} /* endif BitGroom */
|
||||
|
||||
if (quantize_mode == NC_QUANTIZE_GRANULARBG)
|
||||
{
|
||||
if (dest_type == NC_FLOAT)
|
||||
{
|
||||
/* Granular BitGroom */
|
||||
op1.fp = (float *)dest;
|
||||
u32_ptr = op1.ui32p;
|
||||
for (idx = 0L; idx < len; idx++)
|
||||
{
|
||||
|
||||
if((val = op1.fp[idx]) != mss_val_cmp_flt && u32_ptr[idx] != 0U)
|
||||
{
|
||||
mnt = frexp(val, &xpn_bs2); /* DGG19 p. 4102 (8) */
|
||||
mnt_fabs = fabs(mnt);
|
||||
mnt_log10_fabs = log10(mnt_fabs);
|
||||
/* 20211003 Continuous determination of dgt_nbr improves CR by ~10% */
|
||||
dgt_nbr = (int)floor(xpn_bs2 * dgt_per_bit + mnt_log10_fabs) + 1; /* DGG19 p. 4102 (8.67) */
|
||||
qnt_pwr = (int)floor(bit_per_dgt * (dgt_nbr - nsd)); /* DGG19 p. 4101 (7) */
|
||||
prc_bnr_xpl_rqr = mnt_fabs == 0.0 ? 0 : abs((int)floor(xpn_bs2 - bit_per_dgt*mnt_log10_fabs) - qnt_pwr); /* Protect against mnt = -0.0 */
|
||||
prc_bnr_xpl_rqr--; /* 20211003 Reduce formula result by 1 bit: Passes all tests, improves CR by ~10% */
|
||||
|
||||
bit_xpl_nbr_zro = BIT_XPL_NBR_SGN_FLT - prc_bnr_xpl_rqr;
|
||||
msk_f32_u32_zro = 0u; /* Zero all bits */
|
||||
msk_f32_u32_zro = ~msk_f32_u32_zro; /* Turn all bits to ones */
|
||||
/* Bit Shave mask for AND: Left shift zeros into bits to be rounded, leave ones in untouched bits */
|
||||
msk_f32_u32_zro <<= bit_xpl_nbr_zro;
|
||||
/* Bit Set mask for OR: Put ones into bits to be set, zeros in untouched bits */
|
||||
msk_f32_u32_one = ~msk_f32_u32_zro;
|
||||
msk_f32_u32_hshv = msk_f32_u32_one & (msk_f32_u32_zro >> 1); /* Set one bit: the MSB of LSBs */
|
||||
u32_ptr[idx] += msk_f32_u32_hshv; /* Add 1 to the MSB of LSBs, carry 1 to mantissa or even exponent */
|
||||
u32_ptr[idx] &= msk_f32_u32_zro; /* Shave it */
|
||||
|
||||
} /* !mss_val_cmp_flt */
|
||||
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Granular BitGroom */
|
||||
op1.dp = (double *)dest;
|
||||
u64_ptr = op1.ui64p;
|
||||
for (idx = 0L; idx < len; idx++)
|
||||
{
|
||||
|
||||
if((val = op1.dp[idx]) != mss_val_cmp_dbl && u64_ptr[idx] != 0ULL)
|
||||
{
|
||||
mnt = frexp(val, &xpn_bs2); /* DGG19 p. 4102 (8) */
|
||||
mnt_fabs = fabs(mnt);
|
||||
mnt_log10_fabs = log10(mnt_fabs);
|
||||
/* 20211003 Continuous determination of dgt_nbr improves CR by ~10% */
|
||||
dgt_nbr = (int)floor(xpn_bs2 * dgt_per_bit + mnt_log10_fabs) + 1; /* DGG19 p. 4102 (8.67) */
|
||||
qnt_pwr = (int)floor(bit_per_dgt * (dgt_nbr - nsd)); /* DGG19 p. 4101 (7) */
|
||||
prc_bnr_xpl_rqr = mnt_fabs == 0.0 ? 0 : abs((int)floor(xpn_bs2 - bit_per_dgt*mnt_log10_fabs) - qnt_pwr); /* Protect against mnt = -0.0 */
|
||||
prc_bnr_xpl_rqr--; /* 20211003 Reduce formula result by 1 bit: Passes all tests, improves CR by ~10% */
|
||||
|
||||
bit_xpl_nbr_zro = BIT_XPL_NBR_SGN_DBL - prc_bnr_xpl_rqr;
|
||||
msk_f64_u64_zro = 0ull; /* Zero all bits */
|
||||
msk_f64_u64_zro = ~msk_f64_u64_zro; /* Turn all bits to ones */
|
||||
/* Bit Shave mask for AND: Left shift zeros into bits to be rounded, leave ones in untouched bits */
|
||||
msk_f64_u64_zro <<= bit_xpl_nbr_zro;
|
||||
/* Bit Set mask for OR: Put ones into bits to be set, zeros in untouched bits */
|
||||
msk_f64_u64_one = ~msk_f64_u64_zro;
|
||||
msk_f64_u64_hshv = msk_f64_u64_one & (msk_f64_u64_zro >> 1); /* Set one bit: the MSB of LSBs */
|
||||
u64_ptr[idx] += msk_f64_u64_hshv; /* Add 1 to the MSB of LSBs, carry 1 to mantissa or even exponent */
|
||||
u64_ptr[idx] &= msk_f64_u64_zro; /* Shave it */
|
||||
|
||||
} /* !mss_val_cmp_dbl */
|
||||
|
||||
}
|
||||
}
|
||||
} /* endif GranularBG */
|
||||
|
||||
return NC_NOERR;
|
||||
}
|
||||
|
@ -98,10 +98,10 @@ main(int argc, char **argv)
|
||||
if (nc_def_var_quantize(ncid, NC_GLOBAL, NC_QUANTIZE_BITGROOM, NSD_3) != NC_EGLOBAL) ERR;
|
||||
if (nc_def_var_quantize(ncid, varid2 + 1, NC_QUANTIZE_BITGROOM, NSD_3) != NC_ENOTVAR) ERR;
|
||||
/* Invalid values. */
|
||||
if (nc_def_var_quantize(ncid, varid1, NC_QUANTIZE_BITGROOM + 1, NSD_3) != NC_EINVAL) ERR;
|
||||
if (nc_def_var_quantize(ncid, varid1, NC_QUANTIZE_GRANULARBG + 1, NSD_3) != NC_EINVAL) ERR;
|
||||
if (nc_def_var_quantize(ncid, varid1, NC_QUANTIZE_BITGROOM, -1) != NC_EINVAL) ERR;
|
||||
if (nc_def_var_quantize(ncid, varid1, NC_QUANTIZE_BITGROOM, NC_QUANTIZE_MAX_FLOAT_NSD + 1) != NC_EINVAL) ERR;
|
||||
if (nc_def_var_quantize(ncid, varid2, NC_QUANTIZE_BITGROOM + 1, 3) != NC_EINVAL) ERR;
|
||||
if (nc_def_var_quantize(ncid, varid2, NC_QUANTIZE_GRANULARBG + 1, 3) != NC_EINVAL) ERR;
|
||||
if (nc_def_var_quantize(ncid, varid2, NC_QUANTIZE_BITGROOM, -1) != NC_EINVAL) ERR;
|
||||
if (nc_def_var_quantize(ncid, varid2, NC_QUANTIZE_BITGROOM, NC_QUANTIZE_MAX_DOUBLE_NSD + 1) != NC_EINVAL) ERR;
|
||||
if (nc_def_var_quantize(ncid, varid2, NC_QUANTIZE_BITGROOM, 0) != NC_EINVAL) ERR;
|
||||
@ -242,9 +242,9 @@ main(int argc, char **argv)
|
||||
if (quantize_mode_in != NC_QUANTIZE_BITGROOM || nsd_in != NSD_3) ERR;
|
||||
|
||||
/* Each var now has an attribute describing the quantize settings. */
|
||||
if (nc_get_att_int(ncid, 0, NC_QUANTIZE_ATT_NAME, &nsd_att_in)) ERR;
|
||||
if (nc_get_att_int(ncid, 0, NC_QUANTIZE_BITGROOM_ATT_NAME, &nsd_att_in)) ERR;
|
||||
if (nsd_att_in != NSD_3) ERR;
|
||||
if (nc_get_att_int(ncid, 1, NC_QUANTIZE_ATT_NAME, &nsd_att_in)) ERR;
|
||||
if (nc_get_att_int(ncid, 1, NC_QUANTIZE_BITGROOM_ATT_NAME, &nsd_att_in)) ERR;
|
||||
if (nsd_att_in != NSD_3) ERR;
|
||||
|
||||
/* Check the data. */
|
||||
@ -447,9 +447,9 @@ main(int argc, char **argv)
|
||||
if (quantize_mode_in != NC_QUANTIZE_BITGROOM || nsd_in != NSD_3) ERR;
|
||||
|
||||
/* Each var now has an attribute describing the quantize settings. */
|
||||
if (nc_get_att_int(ncid, 0, NC_QUANTIZE_ATT_NAME, &nsd_att_in)) ERR;
|
||||
if (nc_get_att_int(ncid, 0, NC_QUANTIZE_BITGROOM_ATT_NAME, &nsd_att_in)) ERR;
|
||||
if (nsd_att_in != NSD_3) ERR;
|
||||
if (nc_get_att_int(ncid, 1, NC_QUANTIZE_ATT_NAME, &nsd_att_in)) ERR;
|
||||
if (nc_get_att_int(ncid, 1, NC_QUANTIZE_BITGROOM_ATT_NAME, &nsd_att_in)) ERR;
|
||||
if (nsd_att_in != NSD_3) ERR;
|
||||
|
||||
/* Check the data. */
|
||||
|
Loading…
Reference in New Issue
Block a user