#include <iostream>
#include <iomanip>
#include <string>
#include <string.h>
#include <math.h>
#include <cmath>
#include <vector>
#include <list>
#include <set>
#include <map>
#include <algorithm>
#include <utility>
#include <deque>
#include <queue>
#include <functional>

#define rep(i, n) for(int i = 0; i < n; ++i)
#define REP(i, m, n) for(int i = m; i < n; ++i)
#define rrep(i,n) for(int i = n; i >= 0; --i)
#define RREP(i, m, n) for(int i = n; i >= m; --i)
#define llrep(i, n) for(ll i = 0; i < n; ++i)
#define llREP(i, m, n) for(ll i = m; i < n; ++i)
#define llrrep(i,n) for(ll i = n; i >= 0; --i)
#define llRREP(i, m, n) for(ll i = n; i >= m; --i)

using ll = long long;
using ull = unsigned long long;
using pii = std::pair<int, int>;
using pll = std::pair<long long, long long>;
using plpii = std::pair<long long, std::pair<int, int>>;
using pdd = std::pair<double, double>;

using namespace std;

const long long _MOD = 1000000007;
const long long MOD = 998244353;
const int ALPHABET = 27;
const double pi = 3.14159265358979;

template<typename T>
constexpr T binaryPow_mod(T radix, T index, T mod) noexcept {
	radix %= mod;
	T rtv = 1;
	while (index > 0) {
		if (index & 1) {
			rtv *= radix;
			rtv %= mod;
		}

		radix *= radix;
		radix %= mod;

		index = index >> 1;
	}

	return rtv;
}

template<typename T>
constexpr T _gcd(T m, T n) noexcept {
	T g = 1;

	while (m != 0) {
		if (m < n) std::swap(m, n);

		if (m & 1) {
			if (n & 1) m = (m - n) >> 1;
			else n = n >> 1;
		}
		else {
			if (n & 1) {
				m = m >> 1;
			}
			else {
				n = n >> 1;
				m = m >> 1;
				g = g << 1;
			}
		}
	}

	return g * n;
}

int main() {
	cin.tie(0);
	ios::sync_with_stdio(false);

	int n;
	cin >> n;
	pll* ab = new pll[n];
	rep(i, n) cin >> ab[i].first >> ab[i].second;

	map<pll, ll> m;
	rep(i, n) {
		if (ab[i].first == 0 || ab[i].second == 0) {
			if (ab[i].first == 0 && ab[i].second == 0) {
				m[pll(0, 0)] += 1;
			}
			else if(ab[i].first == 0){
				m[pll(0, 1)] += 1;
			}
			else {
				m[pll(1, 0)] += 1;
			}

			continue;
		}

		ll t = _gcd(abs(ab[i].first), abs(ab[i].second));
		if ((ab[i].first < 0 && ab[i].second > 0) || (ab[i].first > 0 && ab[i].second < 0)) {
			m[pll(-abs(ab[i].first / t), abs(ab[i].second / t))] += 1;
		}
		else {
			m[pll(abs(ab[i].first / t), abs(ab[i].second / t))] += 1;
		}
		
	}

	ll zero = 0;
	ll ans = 1;
	for (auto p = m.begin(); p != m.end(); ++p) {
		pair<pll, ll> t = *p;

		if (t.first == pll(0, 0) && t.second != 0) {
			zero = t.second;
			zero %= _MOD;
			m[pll(0, 0)] = 0;
		}
		else if ((t.first == pll(0, 1) || t.first == pll(1, 0)) && t.second != 0) {
			ll x = binaryPow_mod((ll)2, m[pll(0, 1)], _MOD);
			x += binaryPow_mod((ll)2, m[pll(1, 0)], _MOD);
			ans *= x - 1;
			ans %= _MOD;

			m[pll(0, 1)] = 0;
			m[pll(1, 0)] = 0;
		}
		else if (t.second != 0) {
			ll x = binaryPow_mod((ll)2, m[t.first], _MOD);
			x += binaryPow_mod((ll)2, m[pll(abs(t.first.second) * (t.first.first < 0 ? 1 : -1), abs(t.first.first))], _MOD);
			ans *= x - 1;
			ans %= _MOD;

			m[t.first] = 0;
			m[pll(abs(t.first.second) * (t.first.first < 0 ? 1 : -1), abs(t.first.first))] = 0;
		}
	}

	ans += zero - 1;
	ans %= _MOD;
	if (ans < 0) {
		ans += _MOD;
	}

	cout << ans << "\n";

	return 0;
}



Measured memory_bytes: 31732