Files
secondo/Algebras/Standard-C++/RationalAttr.h
2026-01-23 17:03:45 +08:00

712 lines
17 KiB
C++

/*
----
This file is part of SECONDO.
Copyright (C) 2013, University in Hagen, Department of Computer Science,
Database Systems for New Applications.
SECONDO is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
SECONDO is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with SECONDO; if not, write to the Free Software
----
This class implements a rational type in Secondo.
*/
#ifndef RATIONAL_H
#define RATIONAL_H
#include "NestedList.h"
#include "Attribute.h"
#include "IndexableAttribute.h"
#include "ListUtils.h"
#include <limits>
#include "GenericTC.h"
#include <errno.h>
#include "LongInt.h"
/*
Class Rational.
*/
class Rational : public Attribute {
public:
Rational() {}
explicit Rational(bool defined):
Attribute(defined),negative(0),nominator(0), denominator(1){}
Rational(const Rational& r):
Attribute(r.IsDefined()),
negative(r.negative),
nominator(r.nominator),
denominator(r.denominator){}
Rational(const uint64_t v):Attribute(true),
negative(0), nominator(v), denominator(1) {}
Rational(const uint32_t v): Attribute(true),
negative(0), nominator(v), denominator(1){}
Rational(const int64_t v):Attribute(true),
negative(v<0?1:0), nominator(abs(v)), denominator(1) {}
Rational(const int32_t v):Attribute(true),
negative(v<0?1:0), nominator(abs(v)), denominator(1) {}
Rational(const CcInt& v): Attribute(v.IsDefined()){
if(!IsDefined()){
nominator = 0;
denominator = 1;
negative = 0;
} else {
int64_t k = v.GetValue();
negative = k<0?1:0;
nominator = abs(k);
denominator = 1;
}
}
Rational(const LongInt& v): Attribute(v.IsDefined()){
if(!IsDefined()){
nominator = 0;
denominator = 1;
negative = 0;
} else {
int64_t k = v.GetValue();
negative = k<0?1:0;
nominator = abs(k);
denominator = 1;
}
}
Rational(const std::string& v) : Attribute(false){
ReadFromString(v);
}
Rational(const CcString& v) : Attribute(v.IsDefined()){
if(IsDefined()){
ReadFromString(v.GetValue());
} else {
nominator = 0;
denominator = 1;
negative = 0;
}
}
Rational(const CcInt& n, const CcInt& d): Attribute(true){
if(!n.IsDefined() || !d.IsDefined()){
nominator = 0;
denominator = 1;
negative = 0;
SetDefined(false);
return;
}
readFrom(n.GetValue(), d.GetValue());
}
Rational(const CcInt& n, const LongInt& d): Attribute(true){
if(!n.IsDefined() || !d.IsDefined()){
nominator = 0;
denominator = 1;
negative = 0;
SetDefined(false);
return;
}
readFrom(n.GetValue(), d.GetValue());
}
Rational(const LongInt& n, const CcInt& d): Attribute(true){
if(!n.IsDefined() || !d.IsDefined()){
nominator = 0;
denominator = 1;
negative = 0;
SetDefined(false);
return;
}
readFrom(n.GetValue(), d.GetValue());
}
Rational(const LongInt& n, const LongInt& d): Attribute(true){
if(!n.IsDefined() || !d.IsDefined()){
nominator = 0;
denominator = 1;
negative = 0;
SetDefined(false);
return;
}
readFrom(n.GetValue(), d.GetValue());
}
~Rational(){}
const Rational& GetValue() const{
return *this;
}
void readFrom(int64_t n, int64_t d){
if(d==0){
nominator = 0;
denominator = 1;
negative = 0;
SetDefined(false);
return;
}
if(n==0){
nominator = 0;
denominator = 1;
negative = 0;
SetDefined(true);
return;
}
SetDefined(true);
nominator = abs(n);
denominator = abs(d);
negative = (n<0)==(d<0)?0:1;
shorten();
}
Rational& operator=(const Rational& r){
SetDefined(r.IsDefined());
nominator = r.nominator;
denominator = r.denominator;
negative = r.negative;
return *this;
}
bool operator==(const Rational& r) const{
if(!IsDefined()){
return !r.IsDefined();
}
if(!r.IsDefined()){
return false;
}
if((nominator==0) && (r.nominator==0)){
return true;
}
return (nominator==r.nominator)
&& (denominator==r.denominator)
&& (negative == r.negative);
}
bool operator<(const Rational& r) const{
return compareTo(r) < 0;
}
bool operator<=(const Rational& r) const{
return compareTo(r) <= 0;
}
bool operator>=(const Rational& r) const{
return compareTo(r) >= 0;
}
bool operator>(const Rational& r) const{
return compareTo(r) > 0;
}
int compareTo(const Rational & r) const{
if(!IsDefined()){
if(!r.IsDefined()){
return 0;
} else {
return -1;
}
}
if(!r.IsDefined()){
return 1;
}
// this and r are defined
// test for zero
if((nominator==0) && (r.nominator==0)){
return 0;
}
// test for sign
if(negative != r.negative){
return negative==1?-1:1;
}
int cmp1 = abscompare(r);
return negative==0?cmp1:-cmp1;
}
Rational operator*(const Rational& r){
Rational res(*this);
res *=(r);
return res;
}
Rational& operator*=(const Rational& r){
cout << "* called" << endl;
cout << "thhis = " << this->ToString() << endl;
cout << " r = " << r.ToString() << endl;
if(!IsDefined() || !r.IsDefined()){
SetDefined(false);
return *this;
}
uint64_t t1 = euklid(nominator, r.denominator);
uint64_t t2 = euklid(denominator, r.nominator);
nominator = (nominator/t1) * (r.nominator/t2);
denominator = (denominator/t2) * (r.denominator/t1);
negative = (negative != r.negative)?1:0;
return *this;
}
Rational operator/(const Rational& r){
Rational res(*this);
res *=(r.reverse2());
return res;
}
Rational& operator/=(const Rational& r){
(*this) = r.reverse2();
return *this;
}
Rational& operator+=(const Rational& r){
if(negative == r.negative){
uint64_t t1 = euklid(denominator, r.denominator);
nominator = nominator*(r.denominator / t1) +
r.nominator*(denominator/t1);
denominator = denominator * (r.denominator/t1);
return this->shorten();
}
if(r.negative==1){
uint64_t t1 = euklid(denominator, r.denominator);
denominator = denominator * (r.denominator/t1);
uint64_t s1 = nominator*(r.denominator / t1);
uint64_t s2 = r.nominator*(denominator/t1);
if(s1>s2){
nominator = s1-s2;
} else if(s1<s2){
nominator = s2-s1;
negative = 1;
} else {
negative = 0;
nominator = 0;
denominator = 1;
}
return this->shorten();
}
// this is negative, r is positive
uint64_t t1 = euklid(denominator, r.denominator);
denominator = denominator * (r.denominator/t1);
uint64_t s1 = nominator*(r.denominator / t1);
uint64_t s2 = r.nominator*(denominator/t1);
if(s2>s1){
nominator = s2-s1;
negative = 0;
} else if(s2<s1){
nominator = s1-s2;
negative = 1;
} else {
negative = 0;
nominator = 0;
denominator = 1;
}
return this->shorten();
}
Rational operator+(const Rational& r) const{
Rational res(*this);
return res += r;
}
Rational& operator-=(const Rational& r) {
Rational t(r);
t.switchSign();
(*this) +=t;
return *this;
}
Rational operator-(const Rational& r) {
Rational res(*this);
return res -= r;
}
void reverse(){
if(IsDefined()){
if(nominator==0){
SetDefined(false);
} else {
uint64_t tmp = nominator;
nominator = denominator;
denominator = tmp;
}
}
}
Rational reverse2() const{
Rational res(*this);
res.reverse();
return res;
}
void abs(){
negative = 0;
}
Rational abs2(){
Rational res(*this);
res.negative = 0;
return res;
}
/*
Attribute Support
*/
int Compare(const Attribute* arg) const{
return compareTo(*((Rational*)arg));
}
bool Adjacent(const Attribute* arg) const{
return false;
}
size_t Sizeof() const{
return sizeof(*this);
}
size_t HashValue() const{
if(!IsDefined()){
return 0;
}
return (size_t) negative + nominator + denominator;
}
void CopyFrom(const Attribute* arg){
*this = *((Rational*)arg);
}
Rational* Clone() const{
return new Rational(*this);
}
std::string ToString() const{
std::stringstream ss;
if(negative && nominator!=0){
ss << "- ";
}
ss << nominator;
if((nominator!=0) && (denominator!=1)){
ss << " / " << denominator;
}
return ss.str();
}
std::ostream& Print(std::ostream &os) const{
return os << ToString();
}
ListExpr ToListExpr(ListExpr typeInfo) const{
if(!IsDefined()){
return listutils::getUndefined();
}
if(negative){
return nl->ThreeElemList( nl->SymbolAtom("-"),
toListExpr(nominator),
toListExpr(denominator));
} else {
return nl->TwoElemList( toListExpr(nominator),
toListExpr(denominator));
}
}
bool ReadFrom(const ListExpr LE, const ListExpr typeInfo){
if(listutils::isSymbolUndefined(LE)){
SetDefined(false);
return true;
}
if(!nl->HasLength(LE,2) && !nl->HasLength(LE,3)){
return false;
}
char sign = 0;
bool correct = true;
ListExpr LR;
if(nl->HasLength(LE,3)){
sign = getSign(nl->First(LE),correct);
LR = nl->Rest(LE);
} else {
LR = LE;
}
if(!correct) {
return false;
}
uint64_t nom = getUint64(nl->First(LR), correct);
if(!correct) {
return false;
}
uint64_t den = getUint64(nl->Second(LR),correct);
if(!correct){
return false;
}
SetDefined(true);
nominator = nom;
denominator = den;
negative = sign;
if(denominator==0){
nominator=0;
denominator=1;
negative = 0;
SetDefined(false);
}
return true;
}
static const std::string BasicType(){
return "rational";
}
static bool checkType(const ListExpr e){
return listutils::isSymbol(e, BasicType());
}
static bool CheckKind(ListExpr type, ListExpr& errorInfo){
return nl->IsEqual(type,BasicType());
}
static ListExpr Property(){
return gentc::GenProperty("-> DATA",
BasicType(),
"(sign int int)",
"(- 1 3)");
}
// Support for csv import / export
virtual void ReadFromString(std::string value){
bool error=false;
int state = 0;
char neg=0;
uint64_t nom=0;
uint64_t denom=1;
stringutils::trim(value);
for(size_t i=0;i<value.length() && !error;i++){
char c = value[i];
switch (c){
case '+' : if(state==0){
state = 1;
} else {
error=true;
}
break;
case '-' : if(state==0){
state = 1;
neg = 1;
} else {
error=true;
}
break;
case ' ' : if(state==1){
state = 1;
} else if(state==2){
state = 4;
} else if(state==3){
state=3;
} else {
error=true;
}
break;
case '/' : if(state==4){
state = 3;
} else if(state==2){
state = 3;
} else {
error = true;
}
break;
case '0':
case '1':
case '2':
case '3':
case '4':
case '5':
case '6':
case '7':
case '8':
case '9': if(state==0){
nom = getDigit(c);
state = 2;
} else if(state==1){
nom = getDigit(c);
state = 2;
} else if(state==2){
nom = nom*10 + getDigit(c);
} else if(state==3){
denom = getDigit(c);
state = 5;
} else if(state==5){
denom = denom*10 + getDigit(c);
} else {
error=true;
}
break;
default: error = true;
};
}
if(error || ((state!=2) && (state!=5)) || (denom==0)){
nominator=1;
denominator=0;
negative = 0;
SetDefined(false);
} else {
SetDefined(true);
nominator = nom;
denominator = denom;
negative = neg;
}
}
virtual std::string getCsvStr() const{
if(!IsDefined()){
return "undef";
}
std::stringstream res1;
if(negative!=0){
res1 << "-";
}
res1 << nominator << "/" << denominator ;
return res1.str();
}
private:
char negative;
uint64_t nominator;
uint64_t denominator;
static uint64_t euklid(uint64_t a, uint64_t b) {
while(b){
uint64_t h = a % b;
a = b;
b = h;
}
return a;
}
int abscompare(const Rational& r) const{
assert(IsDefined());
assert(r.IsDefined());
uint64_t t1 = euklid(nominator,r.nominator);
uint64_t t2 = euklid(denominator, r.denominator);
uint64_t tl = (nominator/t1 ) * (r.denominator/t2);
uint64_t tr = (r.nominator/t1) * (denominator/t2);
if(tl < tr){
return -1;
} else if(tl>tr){
return 1;
} else {
return 0;
}
}
Rational& shorten(){
uint64_t t = euklid(nominator,denominator);
nominator /= t;
denominator /= t;
return *this;
}
void switchSign(){
negative = negative==0?1:0;
}
static ListExpr toListExpr(uint64_t v){
if(v< (uint32_t)std::numeric_limits<int32_t>::max()){
return nl->IntAtom((int32_t) v);
}
return nl->TwoElemList(
nl->IntAtom( (int32_t) (v>>32)),
nl->IntAtom( (int32_t) (v&0xFFFFFFFF)));
}
static char getSign( const ListExpr e, bool& correct){
correct = false;
if(nl->AtomType(e)!=SymbolType){
return 0;
}
std::string s = nl->SymbolValue(e);
if(s=="-"){
correct = true;
return 1;
}
if(s=="+"){
correct = true;
return 0;
}
return 0;
}
static uint64_t getUint64(const ListExpr e, bool& correct){
if(nl->AtomType(e)==IntType){
uint32_t e2 = nl->IntValue(e);
correct = true;
return e2;
}
if(!nl->HasLength(e,2)){
correct = false;
return 0;
}
ListExpr f = nl->First(e);
ListExpr s = nl->Second(e);
if( (nl->AtomType(f)!=IntType) || (nl->AtomType(s)!=IntType)){
correct = false;
return 0;
}
uint32_t fi = nl->IntValue(f);
uint32_t si = nl->IntValue(s);
uint64_t res = fi;
res = (res << 32) | si;
correct = true;
return res;
}
static uint64_t abs(const int64_t v) {
return v<0?-v:v;
}
static uint32_t getDigit(char c){
return c - '0';
}
};
#endif