source: orange/source/orange/vars.cpp @ 7705:877bf8232fe3

Revision 7705:877bf8232fe3, 21.7 KB checked in by miha <miha.stajdohar@…>, 3 years ago (diff)

tvariable delete operator changed to destructor

Line 
1/*
2    This file is part of Orange.
3
4    Copyright 1996-2010 Faculty of Computer and Information Science, University of Ljubljana
5    Contact: janez.demsar@fri.uni-lj.si
6
7    Orange is free software: you can redistribute it and/or modify
8    it under the terms of the GNU General Public License as published by
9    the Free Software Foundation, either version 3 of the License, or
10    (at your option) any later version.
11
12    Orange is distributed in the hope that it will be useful,
13    but WITHOUT ANY WARRANTY; without even the implied warranty of
14    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15    GNU General Public License for more details.
16
17    You should have received a copy of the GNU General Public License
18    along with Orange.  If not, see <http://www.gnu.org/licenses/>.
19*/
20
21
22// to include Python.h before STL defines a template set (doesn't work with VC 6.0)
23#include "garbage.hpp"
24
25#include <set>
26#include <stack>
27#include <map>
28#include <algorithm>
29#include <queue>
30#include <list>
31#include <float.h>
32#include <locale>
33
34#ifdef DARWIN
35#include <strings.h>
36#endif
37
38#include "stladdon.hpp"
39#include "errors.hpp"
40#include "examples.hpp"
41#include "examplegen.hpp"
42#include "classify.hpp"
43#include "domain.hpp"
44#include "random.hpp"
45#include "orvector.hpp"
46#include "stringvars.hpp"
47
48
49#include "vars.ppp"
50
51typedef multimap<string, TVariable *> MMV;
52
53DEFINE_TOrangeVector_classDescription(PVariable, "TVarList", true, ORANGE_API)
54DEFINE_TOrangeVector_classDescription(PVarList, "TVarListList", true, ORANGE_API)
55
56MMV TVariable::allVariablesMap;
57
58const char *sortedDaNe[] = {"da", "ne", 0 };
59const char *resortedDaNe[] = {"ne", "da", 0};
60
61const char **specialSortCases[] = { sortedDaNe, 0};
62const char **specialCasesResorted[] = { resortedDaNe, 0};
63
64const char *putAtBeginning[] = {"no", "none", "absent", "normal", 0};
65
66TVariable *TVariable::getExisting(const string &name, const int &varType, TStringList *fixedOrderValues, set<string> *values,
67                                  const int failOn, int *status)
68{
69  if ((fixedOrderValues && fixedOrderValues->size() ) && (varType != TValue::INTVAR))
70    ::raiseErrorWho("Variable", "cannot specify the value list for non-discrete attributes");
71
72  if (failOn == TVariable::OK) {
73    if (status)
74      *status = TVariable::OK;
75    return NULL;
76  }
77
78  vector<pair<TVariable *, int> > candidates;
79  TStringList::const_iterator vvi, vve;
80
81   pair<MMV::iterator,MMV::iterator> rp = allVariablesMap.equal_range(name);
82   MMV::iterator it;
83 
84   for (it=rp.first; it!=rp.second; ++it) { 
85     if ((it->second)->varType == varType) {
86
87      int tempStat = TVariable::OK;
88
89      // non-discrete attributes are always ok,
90      // discrete ones need further checking if they have any defined values
91      TEnumVariable *evar = dynamic_cast<TEnumVariable *>(it->second);
92      if (evar && evar->values->size()) {
93
94        if (fixedOrderValues && !evar->checkValuesOrder(*fixedOrderValues))
95          tempStat = TVariable::Incompatible;
96
97        if ((tempStat == TVariable::OK)
98            && (values && values->size() || fixedOrderValues && fixedOrderValues->size())) {
99          for(vvi = evar->values->begin(), vve = evar->values->end();
100              (vvi != vve)
101               && (!values || (values->find(*vvi) == values->end()))
102               && (!fixedOrderValues || (find(fixedOrderValues->begin(), fixedOrderValues->end(), *vvi) == fixedOrderValues->end()));
103              vvi++);
104          if (vvi == vve)
105            tempStat = TVariable::NoRecognizedValues;
106         }
107
108         if ((tempStat == TVariable::OK) && fixedOrderValues) {
109           for(vvi = fixedOrderValues->begin(), vve = fixedOrderValues->end();
110               (vvi != vve) && evar->hasValue(*vvi);
111               vvi++);
112           if (vvi != vve)
113             tempStat = TVariable::MissingValues;
114         }
115
116         if ((tempStat == TVariable::OK) && values) {
117           set<string>::const_iterator vsi(values->begin()), vse(values->end());
118           for(; (vsi != vse) && evar->hasValue(*vsi); vsi++);
119           if (vsi != vse)
120             tempStat = TVariable::MissingValues;
121         }
122       }
123
124      candidates.push_back(make_pair(it->second, tempStat));
125      if (tempStat == TVariable::OK)
126        break;
127    }
128  }
129
130  TVariable *var = NULL;
131
132  int intStatus;
133  if (!status)
134    status = &intStatus;
135  *status = TVariable::NotFound;
136
137  const int actFailOn = failOn > TVariable::Incompatible ? TVariable::Incompatible : failOn;
138  for(vector<pair<TVariable *, int> >::const_iterator ci(candidates.begin()), ce(candidates.end());
139      ci != ce; ci++)
140    if (ci->second < *status) {
141      *status = ci->second;
142      if (*status < actFailOn)
143        var = ci->first;
144    }
145
146  //var = mlnew TEnumVariable(name);
147  TEnumVariable *evar = dynamic_cast<TEnumVariable *>(var);
148  if (evar) {
149    if (fixedOrderValues)
150      const_PITERATE(TStringList, si, fixedOrderValues)
151        evar->addValue(*si);
152
153    if (values) {
154      vector<string> sorted;
155      TEnumVariable::presortValues(*values, sorted);
156      const_ITERATE(vector<string>, ssi, sorted)
157        evar->addValue(*ssi);
158    }
159  }
160
161  return var;
162}
163
164
165TVariable *TVariable::make(const string &name, const int &varType, TStringList *fixedOrderValues, set<string> *values,
166                           const int createNewOn, int *status)
167{
168  int intStatus;
169  if (!status)
170    status = &intStatus;
171
172  TVariable *var;
173  if (createNewOn == TVariable::OK) {
174    var = NULL;
175    *status = TVariable::OK;
176  }
177  else {
178    var = getExisting(name, varType, fixedOrderValues, values, createNewOn, status);
179  }
180
181  if (!var) {
182      switch (varType) {
183        case TValue::INTVAR: {
184          var = mlnew TEnumVariable(name);
185          TEnumVariable *evar = dynamic_cast<TEnumVariable *>(var);
186          if (evar) {
187            if (fixedOrderValues)
188              const_PITERATE(TStringList, si, fixedOrderValues)
189                evar->addValue(*si);
190
191            if (values) {
192              vector<string> sorted;
193              TEnumVariable::presortValues(*values, sorted);
194              const_ITERATE(vector<string>, ssi, sorted)
195                evar->addValue(*ssi);
196            }
197          }
198          break;
199        }
200
201        case TValue::FLOATVAR:
202          var = mlnew TFloatVariable(name);
203          break;
204
205        case STRINGVAR:
206          var = mlnew TStringVariable(name);
207          break;
208      }
209  }
210
211  return var;
212}
213
214
215bool TVariable::isEquivalentTo(const TVariable &old) const {
216  return    (varType == old.varType) && (ordered == old.ordered) && (distributed == old.distributed)
217         && (!sourceVariable || !old.sourceVariable || (sourceVariable == old.sourceVariable))
218         && (!getValueFrom || !old.getValueFrom || (getValueFrom == old.getValueFrom));
219}
220
221
222void TVariable::registerVariable() {
223  allVariablesMap.insert(pair<string, TVariable *>(name, this));
224}
225
226void TVariable::removeVariable() {
227      pair<MMV::iterator,MMV::iterator> rp = allVariablesMap.equal_range(name);
228      MMV::iterator it;
229
230      for (it=rp.first; it!=rp.second; ++it) {
231          if (it->second == this) {
232              allVariablesMap.erase(it);
233              break;
234          }
235      }
236}
237
238TVariable::~TVariable()
239{
240    /* When the program shuts down, it may happen that the list is destroyed before
241       the variables. We do nothing in this case. */
242    if (allVariablesMap.size()) {
243        removeVariable();
244    }
245}
246
247TVariable::TVariable(const int &avarType, const bool &ord)
248: varType(avarType),
249  ordered(ord),
250  distributed(false),
251  getValueFromLocked(false),
252  DC_value(varType, valueDC),
253  DK_value(varType, valueDK),
254  defaultMetaId(0)
255{
256  registerVariable();
257}
258
259
260TVariable::TVariable(const string &aname, const int &avarType, const bool &ord)
261: varType(avarType),
262  ordered(ord),
263  distributed(false),
264  getValueFromLocked(false),
265  DC_value(varType, valueDC),
266  DK_value(varType, valueDK),
267  defaultMetaId(0)
268{ name = aname; 
269  registerVariable();
270};
271
272
273const TValue &TVariable::DC() const
274{ return DC_value; }
275
276
277const TValue &TVariable::DK() const
278{ return DK_value; }
279
280
281TValue  TVariable::specialValue(int spec) const
282{ return TValue(varType, spec); }
283
284/*  Converts a human-readable string, representing the value (as read from the file, for example) to TValue.
285    TVariable::str2val_add interprets ? as DK and ~ as DC; otherwise it sets val.varType to varType, other fields
286    are left intact.*/
287bool TVariable::str2special(const string &valname, TValue &valu) const
288{ if ((valname=="?") || !valname.length()){
289    valu = TValue(DK());
290    return true;
291  }
292  else if (valname=="~") {
293    valu = TValue(DC());
294    return true;
295  }
296  return false;
297}
298
299
300bool TVariable::special2str(const TValue &val, string &str) const
301{ switch (val.valueType) {
302    case 0: return false;
303    case valueDC : str="~"; break;
304    case valueDK : str="?"; break;
305    default: str = ".";
306  }
307  return true;
308}
309
310
311
312bool TVariable::str2val_try(const string &valname, TValue &valu)
313{ try {
314    str2val(valname, valu);
315    return true;
316  } catch (exception) {
317    return false;
318  }
319}
320
321
322void TVariable::str2val_add(const string &valname, TValue &valu)
323{ str2val(valname, valu); }
324
325
326void TVariable::filestr2val(const string &valname, TValue &valu, TExample &)
327{ str2val_add(valname, valu); }
328
329
330void TVariable::val2filestr(const TValue &val, string &str, const TExample &) const
331{ val2str(val, str); }
332
333
334// Calls classifier, specified in getValueFrom, if one is available
335TValue TVariable::computeValue(const TExample &ex)
336{ if (getValueFrom && !getValueFromLocked)
337    try {
338      if (distributed) {
339        getValueFromLocked = true;
340        const PSomeValue val = PSomeValue(getValueFrom->classDistribution(ex));
341        getValueFromLocked = false;
342        return TValue(PSomeValue(val));
343      }
344      else {
345        getValueFromLocked = true;
346        const TValue val = getValueFrom->operator()(ex);
347        getValueFromLocked = false;
348        return val;
349      }
350    }
351    catch (...) {
352      getValueFromLocked = false;
353      throw;
354    }
355  else
356    return DK();
357}
358
359
360bool TVariable::firstValue(TValue &val) const
361{
362  raiseError("attribute '%s' does not support 'firstValue' method", name.c_str());
363  return false;
364}
365
366bool TVariable::nextValue(TValue &val) const
367{
368  raiseError("attribute '%s' does not support 'nextValue' method", name.c_str());
369  return false;
370}
371
372TValue TVariable::randomValue(const int &rand)
373{
374  raiseError("attribute '%s' does not support 'randomValue' method", name.c_str());
375  return TValue();
376}
377
378
379// Sets autoValues to true, maxLen to 2 and varType to TValue::INVAR
380TEnumVariable::TEnumVariable()
381: TVariable(TValue::INTVAR, false),
382  values(mlnew TStringList()),
383  baseValue(-1)
384{}
385
386
387
388TEnumVariable::TEnumVariable(const string &aname)
389: TVariable(aname, TValue::INTVAR, false),
390  values(mlnew TStringList()),
391  baseValue(-1)
392{}
393
394
395TEnumVariable::TEnumVariable(const string &aname, PStringList val)
396: TVariable(aname, TValue::INTVAR, false),
397  values(val),
398  baseValue(-1)
399{}
400
401
402TEnumVariable::TEnumVariable(const TEnumVariable &var)
403: TVariable(var),
404  values(mlnew TStringList(var.values.getReference())),
405  baseValue(var.baseValue)
406{}
407
408
409bool TEnumVariable::isEquivalentTo(const TVariable &old) const
410{
411  TEnumVariable const *eold = dynamic_cast<TEnumVariable const *>(&old);
412
413  if (!eold || !TVariable::isEquivalentTo(old) ||
414         ((baseValue != -1) && (eold->baseValue != -1) && (baseValue != eold->baseValue)))
415     return false;
416
417  TStringList::const_iterator vi1(values->begin()), ve1(values->end());
418  TStringList::const_iterator vi2(eold->values->begin()), ve2(eold->values->end());
419  for(; (vi1 != ve1) && (vi2 != ve2) && (*vi1 == *vi2); vi1++, vi2++);
420  return (vi1 == ve1) || (vi2 == ve2);
421}
422
423
424int  TEnumVariable::noOfValues() const
425{ return values->size(); };
426
427
428bool TEnumVariable::firstValue(TValue &val) const
429{ if (values->size()) {
430    val = TValue(0);
431    return true;
432  }
433  else {
434    val = TValue(DK());
435    return false;
436  }
437}
438
439
440
441bool TEnumVariable::nextValue(TValue &val) const
442{ return (++val.intV<int(values->size())); }
443
444
445
446TValue TEnumVariable::randomValue(const int &rand)
447{
448  if (!randomGenerator)
449    randomGenerator = mlnew TRandomGenerator;
450
451  if (!values->size())
452    raiseErrorWho("randomValue", "no values");
453
454  return TValue(int(rand<=0 ? randomGenerator->randint(values->size()) : rand%values->size()));
455}
456
457
458void TEnumVariable::addValue(const string &val)
459{
460  if (values->size() > 50) {
461    if (valuesTree.empty())
462      createValuesTree();
463
464    map<string, int>::iterator lb = valuesTree.lower_bound(val);
465    if ((lb == valuesTree.end()) || (lb->first != val)) {
466      // watch the order!
467      valuesTree.insert(lb, make_pair(val, values->size()));
468      values->push_back(val);
469    }
470  }
471
472  else {
473    if (!exists(values->begin(), values->end(), val))
474      values->push_back(val);
475
476    if ((values->size() == 5) && ((values->front() == "f") || (values->front() == "float"))) {
477      TStringList::const_iterator vi(values->begin()), ve(values->end());
478      char *eptr;
479      char numtest[32];
480      while(++vi != ve) { // skip the first (f/float)
481        if ((*vi).length() > 31)
482          break;
483
484        strcpy(numtest, (*vi).c_str());
485        for(eptr = numtest; *eptr; eptr++)
486          if (*eptr == ',')
487            *eptr = '.';
488
489        strtod(numtest, &eptr);
490        while (*eptr==32)
491          eptr++;
492
493        if (*eptr)
494          break;
495      }
496
497      if (vi==ve)
498        raiseWarning("is '%s' a continuous attribute unintentionally defined by '%s'?", get_name().c_str(), values->front().c_str());
499    }
500  }
501}
502
503
504bool TEnumVariable::hasValue(const string &s)
505{
506  if (!valuesTree.empty())
507    return valuesTree.lower_bound(s) != valuesTree.end();
508
509  PITERATE(TStringList, vli, values)
510    if (*vli == s)
511      return true;
512
513  return false;
514}
515
516
517/*  Converts a value from string representation to TValue by searching for it in value list.
518    If value is not found, it is added to the list if 'autoValues'==true, else exception is raised. */
519void TEnumVariable::str2val_add(const string &valname, TValue &valu)
520{
521  const int noValues = values->size();
522
523  if (noValues > 50) {
524    if (valuesTree.empty())
525      createValuesTree();
526
527    map<string, int>::iterator lb = valuesTree.lower_bound(valname);
528    if ((lb != valuesTree.end()) && (lb->first == valname))
529      valu = TValue(lb->second);
530    else if (!str2special(valname, valu)) {
531      valuesTree.insert(lb, make_pair(valname, noValues));
532      values->push_back(valname);
533      valu = TValue(noValues);
534    }
535  }
536
537  else {
538    TStringList::iterator vi = find(values->begin(), values->end(), valname);
539    if (vi!=values->end())
540      valu = TValue(int(vi - values->begin()));
541    else if (!str2special(valname, valu)) {
542      addValue(valname);
543      valu = TValue(noValues);
544    }
545  }
546}
547
548
549void TEnumVariable::str2val(const string &valname, TValue &valu)
550{
551  if (values->size() > 50) {
552    if (valuesTree.empty())
553      createValuesTree();
554
555    map<string, int>::const_iterator vi = valuesTree.find(valname);
556    if (vi != valuesTree.end())
557      valu = TValue(vi->second);
558    else if (!str2special(valname, valu))
559      raiseError("attribute '%s' does not have value '%s'", get_name().c_str(), valname.c_str());
560  }
561
562  else {
563    TStringList::const_iterator vi = find(values->begin(), values->end(), valname);
564    if (vi!=values->end())
565      valu = TValue(int(vi - values->begin()));
566    else if (!str2special(valname, valu))
567      raiseError("attribute '%s' does not have value '%s'", get_name().c_str(), valname.c_str());
568  }
569}
570
571
572
573bool TEnumVariable::str2val_try(const string &valname, TValue &valu)
574{
575  if (values->size() > 50) {
576    if (valuesTree.empty())
577      createValuesTree();
578
579    map<string, int>::const_iterator vi = valuesTree.find(valname);
580    if (vi != valuesTree.end()) {
581      valu = TValue(vi->second);
582      return true;
583    }
584    return str2special(valname, valu);
585  }
586
587  else {
588    TStringList::const_iterator vi = find(values->begin(), values->end(), valname);
589    if (vi!=values->end()) {
590      valu = TValue(int(vi - values->begin()));
591      return true;
592    }
593    return str2special(valname, valu);
594  }
595}
596
597
598
599// Converts TValue into a string representation of value. If invalid, string 'ERR' is returned.
600void TEnumVariable::val2str(const TValue &val, string &str) const
601{ if (val.isSpecial()) {
602    special2str(val, str);
603    return;
604  }
605
606  if (val.svalV) {
607    const TDiscDistribution *dval = dynamic_cast<const TDiscDistribution *>(val.svalV.getUnwrappedPtr());
608    if (!dval)
609      raiseError("invalid value type");
610
611    str = "(";
612    char buf[12];
613    const_PITERATE(TDiscDistribution, di, dval) {
614      if (di != dval->begin())
615        str+=", ";
616      sprintf(buf, "%1.3f", *di);
617      str += buf;
618    }
619    str += ")";
620  }
621
622  str = val.intV<int(values->size()) ? values->operator[](val.intV) : "#RNGE";
623}
624
625
626void TEnumVariable::createValuesTree()
627{
628  int i = 0;
629  const_PITERATE(TStringList, vi, values)
630    valuesTree[*vi] = i++;
631}
632
633
634bool TEnumVariable::checkValuesOrder(const TStringList &refValues)
635{
636  for(TStringList::const_iterator ni(refValues.begin()), ne(refValues.end()), ei(values->begin()), ee(values->end());
637      (ei != ee) && (ni != ne); ei++, ni++)
638    if (*ei != *ni)
639      return false;
640  return true;
641}
642
643
644void TEnumVariable::presortValues(const set<string> &unsorted, vector<string> &sorted)
645{
646  sorted.clear();
647  sorted.insert(sorted.begin(), unsorted.begin(), unsorted.end());
648
649  vector<string>::iterator si, se(sorted.end());
650  const char ***ssi, **ssii, ***rssi;
651  for(ssi = specialSortCases, rssi = specialCasesResorted; *ssi; ssi++, rssi++) {
652    for(si = sorted.begin(), ssii = *ssi; *ssii && (si != se) && !stricmp(*ssii, si->c_str()); *ssii++);
653    if (!*ssii && (si==se)) {
654      sorted.clear();
655      sorted.insert(sorted.begin(), *rssi, *rssi + (ssii - *ssi));
656      return;
657    }
658  }
659
660  se = sorted.end();
661  for(ssii = putAtBeginning; *ssii; ssii++) {
662    for(si = sorted.begin(); (si != se) && stricmp(*ssii, si->c_str()); si++);
663    if (si != se) {
664      const string toMove = *si;
665      sorted.erase(si);
666      sorted.insert(sorted.begin(), toMove);
667      break;
668    }
669  }
670}
671
672
673TFloatVariable::TFloatVariable()
674: TVariable(TValue::FLOATVAR, true),
675  startValue(-1.0),
676  endValue(0.0),
677  stepValue(-1.0),
678  numberOfDecimals(3),
679  scientificFormat(false),
680  adjustDecimals(2)
681{}
682
683
684TFloatVariable::TFloatVariable(const string &aname)
685: TVariable(aname, TValue::FLOATVAR, true),
686  startValue(-1.0),
687  endValue(0.0),
688  stepValue(-1.0),
689  numberOfDecimals(3),
690  scientificFormat(false),
691  adjustDecimals(2)
692{}
693
694bool TFloatVariable::isEquivalentTo(const TVariable &old) const
695{
696  TFloatVariable const *eold = dynamic_cast<TFloatVariable const *>(&old);
697  return eold && TVariable::isEquivalentTo(old) &&
698         (startValue == eold->startValue) && (endValue == eold->endValue) && (stepValue == eold->stepValue);
699}
700
701
702bool TFloatVariable::firstValue(TValue &val) const
703{ if ((stepValue<=0) || (startValue<endValue))
704    return false;
705  val = TValue(startValue);
706  return true;
707}
708
709
710bool TFloatVariable::nextValue(TValue &val) const
711{ if (stepValue<=0)
712    return false;
713  return ((val.floatV+=stepValue)<=endValue);
714}
715
716
717TValue TFloatVariable::randomValue(const int &rand)
718{ if ((stepValue<=0) || (startValue>=endValue))
719    raiseError("randomValue: interval not given");
720
721  if (!randomGenerator)
722    randomGenerator = mlnew TRandomGenerator();
723
724  if (rand<0)
725    return TValue(randomGenerator->randfloat(startValue, endValue));
726  else
727    return TValue(float(double(rand)/double(4294967295.0)*(endValue-startValue)+startValue));
728}
729
730
731int  TFloatVariable::noOfValues() const
732{ return stepValue>0 ? int((endValue-startValue)/stepValue) : -1; }
733
734
735inline int getNumberOfDecimals(const char *vals, bool &hasE)
736{
737  const char *valsi;
738  for(valsi = vals; *valsi && ((*valsi<'0') || (*valsi>'9')) && (*valsi != '.'); valsi++);
739  if (!*valsi)
740    return -1;
741
742  if ((*valsi=='e') || (*valsi=='E')) {
743    hasE = true;
744    return 0;
745  }
746
747  for(; *valsi && (*valsi!='.'); valsi++);
748  if (!*valsi)
749    return 0;
750
751  int decimals = 0;
752  for(valsi++; *valsi && (*valsi>='0') && (*valsi<='9'); valsi++, decimals++);
753
754  hasE = hasE || (*valsi == 'e') || (*valsi == 'E');
755  return decimals;
756}
757
758
759int TFloatVariable::str2val_low(const string &valname, TValue &valu)
760{
761  if (str2special(valname, valu))
762    return 1;
763
764  const char *vals;
765  char *tmp = NULL;
766
767  const char radix = *localeconv()->decimal_point;
768  const char notGood = radix=='.' ? ',' : '.';
769  int cp = valname.find(notGood);
770  if (cp!=string::npos) {
771    vals = tmp = strcpy(new char[valname.size()+1], valname.c_str());
772    tmp[cp] = radix;
773  }
774  else
775    vals = valname.c_str();
776
777  float f;
778  int ssr = sscanf(vals, "%f", &f);
779
780  int res;
781
782  if (!ssr || (ssr==(char)EOF)) {
783    res = -1;
784  }
785  else {
786    valu = TValue(f);
787
788    if (((startValue<=endValue) && (stepValue>0) && ((f<startValue) || (f>endValue)))) {
789      res = -2;
790    }
791
792    else {
793      res = 1;
794
795      valu = TValue(f);
796
797      int decimals;
798      switch (adjustDecimals) {
799        case 2:
800          numberOfDecimals = getNumberOfDecimals(vals, scientificFormat);
801          adjustDecimals = 1;
802          break;
803        case 1:
804          decimals = getNumberOfDecimals(vals, scientificFormat);
805          if (decimals > numberOfDecimals)
806            numberOfDecimals = decimals;
807      }
808    }
809  }
810
811  if (tmp)
812    delete tmp;
813
814  return res;
815}
816
817
818void TFloatVariable::str2val(const string &valname, TValue &valu)
819{
820  switch (str2val_low(valname, valu)) {
821    case -1: raiseError("'%s' is not a legal value for continuous attribute '%s'", valname.c_str(), get_name().c_str());
822    case -2: raiseError("value %5.3f out of range %5.3f-%5.3f", valu.floatV, startValue, endValue);
823  }
824}
825
826bool TFloatVariable::str2val_try(const string &valname, TValue &valu)
827{
828  return str2val_low(valname, valu) == 1;
829}
830
831
832void TFloatVariable::val2str(const TValue &valu, string &vname) const
833{ if (valu.isSpecial())
834    special2str(valu, vname);
835  else {
836    char buf[64];
837    const float f = fabs(valu.floatV);
838    if (scientificFormat)
839      sprintf(buf, "%g", valu.floatV);
840    else
841      sprintf(buf, "%.*f", numberOfDecimals, valu.floatV);
842    vname = buf;
843  }
844}
Note: See TracBrowser for help on using the repository browser.