source: orange/source/orange/vars.cpp @ 7667:460a67ca7a5a

Revision 7667:460a67ca7a5a, 21.8 KB checked in by markotoplak, 3 years ago (diff)

Replaced allVariables (a list) with allVariablesMap.

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