Fix rounding error in GDSII driver.

* Bug: In CRL/GdsStream::toGdsDbu(), when converting a physical number,
    in double to a number of GDSII dbu in int32_t, we must not use the
    direct cast int32_t(v) because v can be 2.9999999999 which got
    simply truncated into 2 while we want 3. So now use the rounding
    function std::lrint() and configure it round to the *nearest*
    integer.
       Note that we don't check that the long returned can correctly
    fit into int32_t.
This commit is contained in:
Jean-Paul Chaput 2020-11-12 01:18:47 +01:00
parent acc9405ba3
commit d05539378c
1 changed files with 5 additions and 1 deletions

View File

@ -15,6 +15,8 @@
#include <ctime> #include <ctime>
#include <cmath>
#include <cfenv>
#include <string> #include <string>
#include <sstream> #include <sstream>
#include <fstream> #include <fstream>
@ -377,7 +379,8 @@ namespace {
inline GdsRecord GdsStream::LIBNAME ( string s ) { return GdsRecord(GdsRecord::LIBNAME,s); } inline GdsRecord GdsStream::LIBNAME ( string s ) { return GdsRecord(GdsRecord::LIBNAME,s); }
inline GdsRecord GdsStream::SNAME ( string s ) { return GdsRecord(GdsRecord::SNAME,s); } inline GdsRecord GdsStream::SNAME ( string s ) { return GdsRecord(GdsRecord::SNAME,s); }
inline GdsRecord GdsStream::SNAME ( const Name& n ) { return GdsRecord(GdsRecord::SNAME,getString(n)); } inline GdsRecord GdsStream::SNAME ( const Name& n ) { return GdsRecord(GdsRecord::SNAME,getString(n)); }
inline int32_t GdsStream::toGdsDbu ( DbU::Unit v ) const { return DbU::toPhysical( v, DbU::UnitPower::Unity ) / _metricDbU; } inline int32_t GdsStream::toGdsDbu ( DbU::Unit v ) const
{ return uint32_t( std::lrint( DbU::toPhysical( v, DbU::UnitPower::Unity ) / _metricDbU )); }
GdsStream::GdsStream ( string filename ) GdsStream::GdsStream ( string filename )
@ -385,6 +388,7 @@ namespace {
, _dbuPerUu (Cfg::getParamDouble("gdsDriver.dbuPerUu" ,0.001)->asDouble()) // 1000 , _dbuPerUu (Cfg::getParamDouble("gdsDriver.dbuPerUu" ,0.001)->asDouble()) // 1000
, _metricDbU(Cfg::getParamDouble("gdsDriver.metricDbu",10e-9)->asDouble()) // 1um. , _metricDbU(Cfg::getParamDouble("gdsDriver.metricDbu",10e-9)->asDouble()) // 1um.
{ {
std::fesetround( FE_TONEAREST );
_ostream.open( filename, ios_base::out ); _ostream.open( filename, ios_base::out );
GdsRecord record ( GdsRecord::HEADER ); GdsRecord record ( GdsRecord::HEADER );